home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / WarpQuake / Src / vid_win.c < prev    next >
C/C++ Source or Header  |  2000-05-22  |  72KB  |  3,344 lines

  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. // vid_win.c -- Win32 video driver
  21.  
  22. #include "quakedef.h"
  23. #include "winquake.h"
  24. #include "d_local.h"
  25. #include "resource.h"
  26.  
  27. #define MAX_MODE_LIST    30
  28. #define VID_ROW_SIZE    3
  29.  
  30. qboolean    dibonly;
  31.  
  32. extern int        Minimized;
  33.  
  34. HWND        mainwindow;
  35.  
  36. HWND WINAPI InitializeWindow (HINSTANCE hInstance, int nCmdShow);
  37.  
  38. int            DIBWidth, DIBHeight;
  39. qboolean    DDActive;
  40. RECT        WindowRect;
  41. DWORD        WindowStyle, ExWindowStyle;
  42.  
  43. int            window_center_x, window_center_y, window_x, window_y, window_width, window_height;
  44. RECT        window_rect;
  45.  
  46. static DEVMODE    gdevmode;
  47. static qboolean    startwindowed = 0, windowed_mode_set;
  48. static int        firstupdate = 1;
  49. static qboolean    vid_initialized = false, vid_palettized;
  50. static int        lockcount;
  51. static int        vid_fulldib_on_focus_mode;
  52. static qboolean    force_minimized, in_mode_set, is_mode0x13, force_mode_set;
  53. static int        vid_stretched, windowed_mouse;
  54. static qboolean    palette_changed, syscolchg, vid_mode_set, hide_window, pal_is_nostatic;
  55. static HICON    hIcon;
  56.  
  57. viddef_t    vid;                // global video state
  58.  
  59. #define MODE_WINDOWED            0
  60. #define MODE_SETTABLE_WINDOW    2
  61. #define NO_MODE                    (MODE_WINDOWED - 1)
  62. #define MODE_FULLSCREEN_DEFAULT    (MODE_WINDOWED + 3)
  63.  
  64. // Note that 0 is MODE_WINDOWED
  65. cvar_t        vid_mode = {"vid_mode","0", false};
  66. // Note that 0 is MODE_WINDOWED
  67. cvar_t        _vid_default_mode = {"_vid_default_mode","0", true};
  68. // Note that 3 is MODE_FULLSCREEN_DEFAULT
  69. cvar_t        _vid_default_mode_win = {"_vid_default_mode_win","3", true};
  70. cvar_t        vid_wait = {"vid_wait","0"};
  71. cvar_t        vid_nopageflip = {"vid_nopageflip","0", true};
  72. cvar_t        _vid_wait_override = {"_vid_wait_override", "0", true};
  73. cvar_t        vid_config_x = {"vid_config_x","800", true};
  74. cvar_t        vid_config_y = {"vid_config_y","600", true};
  75. cvar_t        vid_stretch_by_2 = {"vid_stretch_by_2","1", true};
  76. cvar_t        _windowed_mouse = {"_windowed_mouse","0", true};
  77. cvar_t        vid_fullscreen_mode = {"vid_fullscreen_mode","3", true};
  78. cvar_t        vid_windowed_mode = {"vid_windowed_mode","0", true};
  79. cvar_t        block_switch = {"block_switch","0", true};
  80. cvar_t        vid_window_x = {"vid_window_x", "0", true};
  81. cvar_t        vid_window_y = {"vid_window_y", "0", true};
  82.  
  83. typedef struct {
  84.     int        width;
  85.     int        height;
  86. } lmode_t;
  87.  
  88. lmode_t    lowresmodes[] = {
  89.     {320, 200},
  90.     {320, 240},
  91.     {400, 300},
  92.     {512, 384},
  93. };
  94.  
  95. int            vid_modenum = NO_MODE;
  96. int            vid_testingmode, vid_realmode;
  97. double        vid_testendtime;
  98. int            vid_default = MODE_WINDOWED;
  99. static int    windowed_default;
  100.  
  101. modestate_t    modestate = MS_UNINIT;
  102.  
  103. static byte        *vid_surfcache;
  104. static int        vid_surfcachesize;
  105. static int        VID_highhunkmark;
  106.  
  107. unsigned char    vid_curpal[256*3];
  108.  
  109. unsigned short    d_8to16table[256];
  110. unsigned    d_8to24table[256];
  111.  
  112. int     driver = grDETECT,mode;
  113. bool    useWinDirect = true, useDirectDraw = true;
  114. MGLDC    *mgldc = NULL,*memdc = NULL,*dibdc = NULL,*windc = NULL;
  115.  
  116. typedef struct {
  117.     modestate_t    type;
  118.     int            width;
  119.     int            height;
  120.     int            modenum;
  121.     int            mode13;
  122.     int            stretched;
  123.     int            dib;
  124.     int            fullscreen;
  125.     int            bpp;
  126.     int            halfscreen;
  127.     char        modedesc[13];
  128. } vmode_t;
  129.  
  130. static vmode_t    modelist[MAX_MODE_LIST];
  131. static int        nummodes;
  132. static vmode_t    *pcurrentmode;
  133.  
  134. int        aPage;                    // Current active display page
  135. int        vPage;                    // Current visible display page
  136. int        waitVRT = true;            // True to wait for retrace on flip
  137.  
  138. static vmode_t    badmode;
  139.  
  140. static byte    backingbuf[48*24];
  141.  
  142. void VID_MenuDraw (void);
  143. void VID_MenuKey (int key);
  144.  
  145. LONG WINAPI MainWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  146. void AppActivate(BOOL fActive, BOOL minimize);
  147.  
  148.  
  149. /*
  150. ================
  151. VID_RememberWindowPos
  152. ================
  153. */
  154. void VID_RememberWindowPos (void)
  155. {
  156.     RECT    rect;
  157.  
  158.     if (GetWindowRect (mainwindow, &rect))
  159.     {
  160.         if ((rect.left < GetSystemMetrics (SM_CXSCREEN)) &&
  161.             (rect.top < GetSystemMetrics (SM_CYSCREEN))  &&
  162.             (rect.right > 0)                             &&
  163.             (rect.bottom > 0))
  164.         {
  165.             Cvar_SetValue ("vid_window_x", (float)rect.left);
  166.             Cvar_SetValue ("vid_window_y", (float)rect.top);
  167.         }
  168.     }
  169. }
  170.  
  171.  
  172. /*
  173. ================
  174. VID_CheckWindowXY
  175. ================
  176. */
  177. void VID_CheckWindowXY (void)
  178. {
  179.  
  180.     if (((int)vid_window_x.value > (GetSystemMetrics (SM_CXSCREEN) - 160)) ||
  181.         ((int)vid_window_y.value > (GetSystemMetrics (SM_CYSCREEN) - 120)) ||
  182.         ((int)vid_window_x.value < 0)                                       ||
  183.         ((int)vid_window_y.value < 0))
  184.     {
  185.         Cvar_SetValue ("vid_window_x", 0.0);
  186.         Cvar_SetValue ("vid_window_y", 0.0 );
  187.     }
  188. }
  189.  
  190.  
  191. /*
  192. ================
  193. VID_UpdateWindowStatus
  194. ================
  195. */
  196. void VID_UpdateWindowStatus (void)
  197. {
  198.  
  199.     window_rect.left = window_x;
  200.     window_rect.top = window_y;
  201.     window_rect.right = window_x + window_width;
  202.     window_rect.bottom = window_y + window_height;
  203.     window_center_x = (window_rect.left + window_rect.right) / 2;
  204.     window_center_y = (window_rect.top + window_rect.bottom) / 2;
  205.  
  206.     IN_UpdateClipCursor ();
  207. }
  208.  
  209.  
  210. /*
  211. ================
  212. ClearAllStates
  213. ================
  214. */
  215. void ClearAllStates (void)
  216. {
  217.     int        i;
  218.     
  219. // send an up event for each key, to make sure the server clears them all
  220.     for (i=0 ; i<256 ; i++)
  221.     {
  222.         Key_Event (i, false);
  223.     }
  224.  
  225.     Key_ClearStates ();
  226.     IN_ClearStates ();
  227. }
  228.  
  229.  
  230. /*
  231. ================
  232. VID_CheckAdequateMem
  233. ================
  234. */
  235. qboolean VID_CheckAdequateMem (int width, int height)
  236. {
  237.     int        tbuffersize;
  238.  
  239.     tbuffersize = width * height * sizeof (*d_pzbuffer);
  240.  
  241.     tbuffersize += D_SurfaceCacheForRes (width, height);
  242.  
  243. // see if there's enough memory, allowing for the normal mode 0x13 pixel,
  244. // z, and surface buffers
  245.     if ((host_parms.memsize - tbuffersize + SURFCACHE_SIZE_AT_320X200 +
  246.          0x10000 * 3) < minimum_memory)
  247.     {
  248.         return false;        // not enough memory for mode
  249.     }
  250.  
  251.     return true;
  252. }
  253.  
  254.  
  255. /*
  256. ================
  257. VID_AllocBuffers
  258. ================
  259. */
  260. qboolean VID_AllocBuffers (int width, int height)
  261. {
  262.     int        tsize, tbuffersize;
  263.  
  264.     tbuffersize = width * height * sizeof (*d_pzbuffer);
  265.  
  266.     tsize = D_SurfaceCacheForRes (width, height);
  267.  
  268.     tbuffersize += tsize;
  269.  
  270. // see if there's enough memory, allowing for the normal mode 0x13 pixel,
  271. // z, and surface buffers
  272.     if ((host_parms.memsize - tbuffersize + SURFCACHE_SIZE_AT_320X200 +
  273.          0x10000 * 3) < minimum_memory)
  274.     {
  275.         Con_SafePrintf ("Not enough memory for video mode\n");
  276.         return false;        // not enough memory for mode
  277.     }
  278.  
  279.     vid_surfcachesize = tsize;
  280.  
  281.     if (d_pzbuffer)
  282.     {
  283.         D_FlushCaches ();
  284.         Hunk_FreeToHighMark (VID_highhunkmark);
  285.         d_pzbuffer = NULL;
  286.     }
  287.  
  288.     VID_highhunkmark = Hunk_HighMark ();
  289.  
  290.     d_pzbuffer = Hunk_HighAllocName (tbuffersize, "video");
  291.  
  292.     vid_surfcache = (byte *)d_pzbuffer +
  293.             width * height * sizeof (*d_pzbuffer);
  294.     
  295.     return true;
  296. }
  297.  
  298.  
  299. void initFatalError(void)
  300. {
  301.     MGL_exit();
  302.     MGL_fatalError(MGL_errorMsg(MGL_result()));
  303.     exit(EXIT_FAILURE);
  304. }
  305.  
  306.  
  307. int VID_Suspend (MGLDC *dc,m_int flags)
  308. {
  309.  
  310.     if (flags & MGL_DEACTIVATE)
  311.     {
  312.     // FIXME: this doesn't currently work on NT
  313.         if (block_switch.value && !WinNT)
  314.         {
  315.             return MGL_NO_DEACTIVATE;
  316.         }
  317.  
  318.         S_BlockSound ();
  319.         S_ClearBuffer ();
  320.  
  321.         IN_RestoreOriginalMouseState ();
  322.         CDAudio_Pause ();
  323.  
  324.     // keep WM_PAINT from trying to redraw
  325.         in_mode_set = true;
  326.  
  327.         block_drawing = true;    // so we don't try to draw while switched away
  328.  
  329.         return MGL_NO_SUSPEND_APP;
  330.     }
  331.     else if (flags & MGL_REACTIVATE)
  332.     {
  333.         IN_SetQuakeMouseState ();
  334.     // fix the leftover Alt from any Alt-Tab or the like that switched us away
  335.         ClearAllStates ();
  336.         CDAudio_Resume ();
  337.         S_UnblockSound ();
  338.  
  339.         in_mode_set = false;
  340.  
  341.         vid.recalc_refdef = 1;
  342.  
  343.         block_drawing = false;
  344.  
  345.         return MGL_NO_SUSPEND_APP;
  346.     }
  347.  
  348. }
  349.  
  350.  
  351. void registerAllDispDrivers(void)
  352. {
  353.     /* Event though these driver require WinDirect, we register
  354.      * them so that they will still be available even if DirectDraw
  355.      * is present and the user has disable the high performance
  356.      * WinDirect modes.
  357.      */
  358.     MGL_registerDriver(MGL_VGA8NAME,VGA8_driver);
  359. //    MGL_registerDriver(MGL_VGAXNAME,VGAX_driver);
  360.  
  361.     /* Register display drivers */
  362.     if (useWinDirect)
  363.     {
  364. //we don't want VESA 1.X drivers        MGL_registerDriver(MGL_SVGA8NAME,SVGA8_driver);
  365.         MGL_registerDriver(MGL_LINEAR8NAME,LINEAR8_driver);
  366.  
  367.         if (!COM_CheckParm ("-novbeaf"))
  368.             MGL_registerDriver(MGL_ACCEL8NAME,ACCEL8_driver);
  369.     }
  370.  
  371.     if (useDirectDraw)
  372.     {
  373.         MGL_registerDriver(MGL_DDRAW8NAME,DDRAW8_driver);
  374.     }
  375. }
  376.  
  377.  
  378. void registerAllMemDrivers(void)
  379. {
  380.     /* Register memory context drivers */
  381.     MGL_registerDriver(MGL_PACKED8NAME,PACKED8_driver);
  382. }
  383.  
  384.  
  385. void VID_InitMGLFull (HINSTANCE hInstance)
  386. {
  387.     int            i, xRes, yRes, bits, vMode, lowres, curmode, temp;
  388.     int            lowstretchedres, stretchedmode, lowstretched;
  389.     uchar        *m;
  390.  
  391. // FIXME: NT is checked for because MGL currently has a bug that causes it
  392. // to try to use WinDirect modes even on NT
  393.     if (COM_CheckParm("-nowindirect") ||
  394.         COM_CheckParm("-nowd") ||
  395.         COM_CheckParm("-novesa") ||
  396.         WinNT)
  397.     {
  398.         useWinDirect = false;
  399.     }
  400.  
  401.     if (COM_CheckParm("-nodirectdraw") || COM_CheckParm("-noddraw") || COM_CheckParm("-nodd"))
  402.         useDirectDraw = false;
  403.  
  404.     // Initialise the MGL
  405.     MGL_unregisterAllDrivers();
  406.     registerAllDispDrivers();
  407.     registerAllMemDrivers();
  408.     MGL_detectGraph(&driver,&mode);
  409.     m = MGL_availableModes();
  410.  
  411.     if (m[0] != 0xFF)
  412.     {
  413.         lowres = lowstretchedres = 99999;
  414.         lowstretched = 0;
  415.         curmode = 0;
  416.  
  417.     // find the lowest-res mode, or a mode we can stretch up to and get
  418.     // lowest-res that way
  419.         for (i = 0; m[i] != 0xFF; i++)
  420.         {
  421.             MGL_modeResolution(m[i], &xRes, &yRes,&bits);
  422.  
  423.             if ((bits == 8) &&
  424.                 (xRes <= MAXWIDTH) &&
  425.                 (yRes <= MAXHEIGHT) &&
  426.                 (curmode < MAX_MODE_LIST))
  427.             {
  428.                 if (m[i] == grVGA_320x200x256)
  429.                     is_mode0x13 = true;
  430.  
  431.                 if (!COM_CheckParm("-noforcevga"))
  432.                 {
  433.                     if (m[i] == grVGA_320x200x256)
  434.                     {
  435.                         mode = i;
  436.                         break;
  437.                     }
  438.                 }
  439.  
  440.                 if (xRes < lowres)
  441.                 {
  442.                     lowres = xRes;
  443.                     mode = i;
  444.                 }
  445.  
  446.                 if ((xRes < lowstretchedres) && ((xRes >> 1) >= 320))
  447.                 {
  448.                     lowstretchedres = xRes >> 1;
  449.                     stretchedmode = i;
  450.                 }
  451.             }
  452.  
  453.             curmode++;
  454.         }
  455.  
  456.     // if there's a mode we can stretch by 2 up to, thereby effectively getting
  457.     // a lower-res mode than the lowest-res real but still at least 320x200, that
  458.     // will be our default mode
  459.         if (lowstretchedres < lowres)
  460.         {
  461.             mode = stretchedmode;
  462.             lowres = lowstretchedres;
  463.             lowstretched = 1;
  464.         }
  465.  
  466.     // build the mode list, leaving room for the low-res stretched mode, if any
  467.         nummodes++;        // leave room for default mode
  468.  
  469.         for (i = 0; m[i] != 0xFF; i++)
  470.         {
  471.             MGL_modeResolution(m[i], &xRes, &yRes,&bits);
  472.  
  473.             if ((bits == 8) &&
  474.                 (xRes <= MAXWIDTH) &&
  475.                 (yRes <= MAXHEIGHT) &&
  476.                 (nummodes < MAX_MODE_LIST))
  477.             {
  478.                 if (i == mode)
  479.                 {
  480.                     if (lowstretched)
  481.                     {
  482.                         stretchedmode = nummodes;
  483.                         curmode = nummodes++;
  484.                     }
  485.                     else
  486.                     {
  487.                         curmode = MODE_FULLSCREEN_DEFAULT;
  488.                     }
  489.                 }
  490.                 else
  491.                 {
  492.                     curmode = nummodes++;
  493.                 }
  494.  
  495.                 modelist[curmode].type = MS_FULLSCREEN;
  496.                 modelist[curmode].width = xRes;
  497.                 modelist[curmode].height = yRes;
  498.                 sprintf (modelist[curmode].modedesc, "%dx%d", xRes, yRes);
  499.  
  500.                 if (m[i] == grVGA_320x200x256)
  501.                     modelist[curmode].mode13 = 1;
  502.                 else
  503.                     modelist[curmode].mode13 = 0;
  504.  
  505.                 modelist[curmode].modenum = m[i];
  506.                 modelist[curmode].stretched = 0;
  507.                 modelist[curmode].dib = 0;
  508.                 modelist[curmode].fullscreen = 1;
  509.                 modelist[curmode].halfscreen = 0;
  510.                 modelist[curmode].bpp = 8;
  511.             }
  512.         }
  513.  
  514.         if (lowstretched)
  515.         {
  516.             modelist[MODE_FULLSCREEN_DEFAULT] = modelist[stretchedmode];
  517.             modelist[MODE_FULLSCREEN_DEFAULT].stretched = 1;
  518.             modelist[MODE_FULLSCREEN_DEFAULT].width >>= 1;
  519.             modelist[MODE_FULLSCREEN_DEFAULT].height >>= 1;
  520.             sprintf (modelist[MODE_FULLSCREEN_DEFAULT].modedesc, "%dx%d",
  521.                      modelist[MODE_FULLSCREEN_DEFAULT].width,
  522.                      modelist[MODE_FULLSCREEN_DEFAULT].height);
  523.         }
  524.  
  525.         vid_default = MODE_FULLSCREEN_DEFAULT;
  526.  
  527.         temp = m[0];
  528.  
  529.         if (!MGL_init(&driver, &temp, ""))
  530.         {
  531.             initFatalError();
  532.         }
  533.     }
  534.  
  535.     MGL_setSuspendAppCallback(VID_Suspend);
  536. }
  537.  
  538.  
  539. MGLDC *createDisplayDC(int forcemem)
  540. /****************************************************************************
  541. *
  542. * Function:     createDisplayDC
  543. * Returns:      Pointer to the MGL device context to use for the application
  544. *
  545. * Description:  Initialises the MGL and creates an appropriate display
  546. *               device context to be used by the GUI. This creates and
  547. *               apropriate device context depending on the system being
  548. *               compile for, and should be the only place where system
  549. *               specific code is required.
  550. *
  551. ****************************************************************************/
  552. {
  553.     MGLDC            *dc;
  554.     pixel_format_t    pf;
  555.     int                npages;
  556.  
  557.     // Start the specified video mode
  558.     if (!MGL_changeDisplayMode(mode))
  559.         initFatalError();
  560.  
  561.     npages = MGL_availablePages(mode);
  562.  
  563.     if (npages > 3)
  564.         npages = 3;
  565.  
  566.     if (!COM_CheckParm ("-notriplebuf"))
  567.     {
  568.         if (npages > 2)
  569.         {
  570.             npages = 2;
  571.         }
  572.     }
  573.  
  574.     if ((dc = MGL_createDisplayDC(npages)) == NULL)
  575.         return NULL;
  576.  
  577.     if (!forcemem && (MGL_surfaceAccessType(dc)) == MGL_LINEAR_ACCESS && (dc->mi.maxPage > 0))
  578.     {
  579.         MGL_makeCurrentDC(dc);
  580.         memdc = NULL;
  581.     }
  582.     else
  583.     {
  584.         // Set up for blitting from a memory buffer
  585.         memdc = MGL_createMemoryDC(MGL_sizex(dc)+1,MGL_sizey(dc)+1,8,&pf);
  586.         MGL_makeCurrentDC(memdc);
  587.     }
  588.  
  589.     // Enable page flipping even for even for blitted surfaces
  590.     if (forcemem)
  591.     {
  592.         vid.numpages = 1;
  593.     }
  594.     else
  595.     {
  596.         vid.numpages = dc->mi.maxPage + 1;
  597.  
  598.         if (vid.numpages > 1)
  599.         {
  600.             // Set up for page flipping
  601.             MGL_setActivePage(dc, aPage = 1);
  602.             MGL_setVisualPage(dc, vPage = 0, false);
  603.         }
  604.  
  605.         if (vid.numpages > 3)
  606.             vid.numpages = 3;
  607.     }
  608.  
  609.     if (vid.numpages == 2)
  610.         waitVRT = true;
  611.     else
  612.         waitVRT = false;
  613.  
  614.     return dc;
  615. }
  616.  
  617.  
  618. void VID_InitMGLDIB (HINSTANCE hInstance)
  619. {
  620.     WNDCLASS        wc;
  621.     HDC                hdc;
  622.     int                i;
  623.  
  624.     hIcon = LoadIcon (hInstance, MAKEINTRESOURCE (IDI_ICON2));
  625.  
  626.     /* Register the frame class */
  627.     wc.style         = 0;
  628.     wc.lpfnWndProc   = (WNDPROC)MainWndProc;
  629.     wc.cbClsExtra    = 0;
  630.     wc.cbWndExtra    = 0;
  631.     wc.hInstance     = hInstance;
  632.     wc.hIcon         = 0;
  633.     wc.hCursor       = LoadCursor (NULL,IDC_ARROW);
  634.     wc.hbrBackground = NULL;
  635.     wc.lpszMenuName  = 0;
  636.     wc.lpszClassName = "WinQuake";
  637.  
  638.     if (!RegisterClass (&wc) )
  639.         Sys_Error ("Couldn't register window class");
  640.  
  641.     /* Find the size for the DIB window */
  642.     /* Initialise the MGL for windowed operation */
  643.     MGL_setAppInstance(hInstance);
  644.     registerAllMemDrivers();
  645.     MGL_initWindowed("");
  646.  
  647.     modelist[0].type = MS_WINDOWED;
  648.     modelist[0].width = 320;
  649.     modelist[0].height = 240;
  650.     strcpy (modelist[0].modedesc, "320x240");
  651.     modelist[0].mode13 = 0;
  652.     modelist[0].modenum = MODE_WINDOWED;
  653.     modelist[0].stretched = 0;
  654.     modelist[0].dib = 1;
  655.     modelist[0].fullscreen = 0;
  656.     modelist[0].halfscreen = 0;
  657.     modelist[0].bpp = 8;
  658.  
  659.     modelist[1].type = MS_WINDOWED;
  660.     modelist[1].width = 640;
  661.     modelist[1].height = 480;
  662.     strcpy (modelist[1].modedesc, "640x480");
  663.     modelist[1].mode13 = 0;
  664.     modelist[1].modenum = MODE_WINDOWED + 1;
  665.     modelist[1].stretched = 1;
  666.     modelist[1].dib = 1;
  667.     modelist[1].fullscreen = 0;
  668.     modelist[1].halfscreen = 0;
  669.     modelist[1].bpp = 8;
  670.  
  671.     modelist[2].type = MS_WINDOWED;
  672.     modelist[2].width = 800;
  673.     modelist[2].height = 600;
  674.     strcpy (modelist[2].modedesc, "800x600");
  675.     modelist[2].mode13 = 0;
  676.     modelist[2].modenum = MODE_WINDOWED + 2;
  677.     modelist[2].stretched = 1;
  678.     modelist[2].dib = 1;
  679.     modelist[2].fullscreen = 0;
  680.     modelist[2].halfscreen = 0;
  681.     modelist[2].bpp = 8;
  682.  
  683. // automatically stretch the default mode up if > 640x480 desktop resolution
  684.     hdc = GetDC(NULL);
  685.  
  686.     if ((GetDeviceCaps(hdc, HORZRES) > 640) && !COM_CheckParm("-noautostretch"))
  687.     {
  688.         vid_default = MODE_WINDOWED + 1;
  689.     }
  690.     else
  691.     {
  692.         vid_default = MODE_WINDOWED;
  693.     }
  694.  
  695.     windowed_default = vid_default;
  696.  
  697.     ReleaseDC(NULL,hdc);
  698.  
  699.     nummodes = 3;    // reserve space for windowed mode
  700.  
  701.     DDActive = 0;
  702. }
  703.  
  704.  
  705. /*
  706. =================
  707. VID_InitFullDIB
  708. =================
  709. */
  710. void VID_InitFullDIB (HINSTANCE hInstance)
  711. {
  712.     DEVMODE    devmode;
  713.     int        i, j, modenum, cmodes, existingmode, originalnummodes, lowestres;
  714.     int        numlowresmodes, bpp, done;
  715.     int        cstretch, istretch, mstretch;
  716.     BOOL    stat;
  717.  
  718. // enumerate 8 bpp modes
  719.     originalnummodes = nummodes;
  720.     modenum = 0;
  721.     lowestres = 99999;
  722.  
  723.     do
  724.     {
  725.         stat = EnumDisplaySettings (NULL, modenum, &devmode);
  726.  
  727.         if ((devmode.dmBitsPerPel == 8) &&
  728.             (devmode.dmPelsWidth <= MAXWIDTH) &&
  729.             (devmode.dmPelsHeight <= MAXHEIGHT) &&
  730.             (nummodes < MAX_MODE_LIST))
  731.         {
  732.             devmode.dmFields = DM_BITSPERPEL |
  733.                                DM_PELSWIDTH |
  734.                                DM_PELSHEIGHT;
  735.  
  736.             if (ChangeDisplaySettings (&devmode, CDS_TEST | CDS_FULLSCREEN) ==
  737.                     DISP_CHANGE_SUCCESSFUL)
  738.             {
  739.                 modelist[nummodes].type = MS_FULLDIB;
  740.                 modelist[nummodes].width = devmode.dmPelsWidth;
  741.                 modelist[nummodes].height = devmode.dmPelsHeight;
  742.                 modelist[nummodes].modenum = 0;
  743.                 modelist[nummodes].mode13 = 0;
  744.                 modelist[nummodes].stretched = 0;
  745.                 modelist[nummodes].halfscreen = 0;
  746.                 modelist[nummodes].dib = 1;
  747.                 modelist[nummodes].fullscreen = 1;
  748.                 modelist[nummodes].bpp = devmode.dmBitsPerPel;
  749.                 sprintf (modelist[nummodes].modedesc, "%dx%d",
  750.                          devmode.dmPelsWidth, devmode.dmPelsHeight);
  751.  
  752.             // if the width is more than twice the height, reduce it by half because this
  753.             // is probably a dual-screen monitor
  754.                 if (!COM_CheckParm("-noadjustaspect"))
  755.                 {
  756.                     if (modelist[nummodes].width > (modelist[nummodes].height << 1))
  757.                     {
  758.                         modelist[nummodes].width >>= 1;
  759.                         modelist[nummodes].halfscreen = 1;
  760.                         sprintf (modelist[nummodes].modedesc, "%dx%d",
  761.                                  modelist[nummodes].width,
  762.                                  modelist[nummodes].height);
  763.                     }
  764.                 }
  765.  
  766.                 for (i=originalnummodes, existingmode = 0 ; i<nummodes ; i++)
  767.                 {
  768.                     if ((modelist[nummodes].width == modelist[i].width) &&
  769.                         (modelist[nummodes].height == modelist[i].height))
  770.                     {
  771.                         existingmode = 1;
  772.                         break;
  773.                     }
  774.                 }
  775.  
  776.                 if (!existingmode)
  777.                 {
  778.                     if (modelist[nummodes].width < lowestres)
  779.                         lowestres = modelist[nummodes].width;
  780.  
  781.                     nummodes++;
  782.                 }
  783.             }
  784.         }
  785.  
  786.         modenum++;
  787.     } while (stat);
  788.  
  789. // see if any of them were actually settable; if so, this is our mode list,
  790. // else enumerate all modes; our mode list is whichever ones are settable
  791. // with > 8 bpp
  792.     if (nummodes == originalnummodes)
  793.     {
  794.         modenum = 0;
  795.         lowestres = 99999;
  796.  
  797.         Con_SafePrintf ("No 8-bpp fullscreen DIB modes found\n");
  798.  
  799.         do
  800.         {
  801.             stat = EnumDisplaySettings (NULL, modenum, &devmode);
  802.  
  803.             if ((((devmode.dmPelsWidth <= MAXWIDTH) &&
  804.                   (devmode.dmPelsHeight <= MAXHEIGHT)) ||
  805.                  (!COM_CheckParm("-noadjustaspect") &&
  806.                   (devmode.dmPelsWidth <= (MAXWIDTH*2)) &&
  807.                   (devmode.dmPelsWidth > (devmode.dmPelsHeight*2)))) &&
  808.                 (nummodes < MAX_MODE_LIST) &&
  809.                 (devmode.dmBitsPerPel > 8))
  810.             {
  811.                 devmode.dmFields = DM_BITSPERPEL |
  812.                                    DM_PELSWIDTH |
  813.                                    DM_PELSHEIGHT;
  814.  
  815.                 if (ChangeDisplaySettings (&devmode, CDS_TEST | CDS_FULLSCREEN) ==
  816.                         DISP_CHANGE_SUCCESSFUL)
  817.                 {
  818.                     modelist[nummodes].type = MS_FULLDIB;
  819.                     modelist[nummodes].width = devmode.dmPelsWidth;
  820.                     modelist[nummodes].height = devmode.dmPelsHeight;
  821.                     modelist[nummodes].modenum = 0;
  822.                     modelist[nummodes].mode13 = 0;
  823.                     modelist[nummodes].stretched = 0;
  824.                     modelist[nummodes].halfscreen = 0;
  825.                     modelist[nummodes].dib = 1;
  826.                     modelist[nummodes].fullscreen = 1;
  827.                     modelist[nummodes].bpp = devmode.dmBitsPerPel;
  828.                     sprintf (modelist[nummodes].modedesc, "%dx%d",
  829.                              devmode.dmPelsWidth, devmode.dmPelsHeight);
  830.  
  831.                 // if the width is more than twice the height, reduce it by half because this
  832.                 // is probably a dual-screen monitor
  833.                     if (!COM_CheckParm("-noadjustaspect"))
  834.                     {
  835.                         if (modelist[nummodes].width > (modelist[nummodes].height*2))
  836.                         {
  837.                             modelist[nummodes].width >>= 1;
  838.                             modelist[nummodes].halfscreen = 1;
  839.                             sprintf (modelist[nummodes].modedesc, "%dx%d",
  840.                                      modelist[nummodes].width,
  841.                                      modelist[nummodes].height);
  842.                         }
  843.                     }
  844.  
  845.                     for (i=originalnummodes, existingmode = 0 ; i<nummodes ; i++)
  846.                     {
  847.                         if ((modelist[nummodes].width == modelist[i].width) &&
  848.                             (modelist[nummodes].height == modelist[i].height))
  849.                         {
  850.                         // pick the lowest available bpp
  851.                             if (modelist[nummodes].bpp < modelist[i].bpp)
  852.                                 modelist[i] = modelist[nummodes];
  853.  
  854.                             existingmode = 1;
  855.                             break;
  856.                         }
  857.                     }
  858.  
  859.                     if (!existingmode)
  860.                     {
  861.                         if (modelist[nummodes].width < lowestres)
  862.                             lowestres = modelist[nummodes].width;
  863.  
  864.                         nummodes++;
  865.                     }
  866.                 }
  867.             }
  868.  
  869.             modenum++;
  870.         } while (stat);
  871.     }
  872.  
  873. // see if there are any low-res modes that aren't being reported
  874.     numlowresmodes = sizeof(lowresmodes) / sizeof(lowresmodes[0]);
  875.     bpp = 8;
  876.     done = 0;
  877.  
  878. // first make sure the driver doesn't just answer yes to all tests
  879.     devmode.dmBitsPerPel = 8;
  880.     devmode.dmPelsWidth = 42;
  881.     devmode.dmPelsHeight = 37;
  882.     devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
  883.  
  884.     if (ChangeDisplaySettings (&devmode, CDS_TEST | CDS_FULLSCREEN) ==
  885.             DISP_CHANGE_SUCCESSFUL)
  886.     {
  887.         done = 1;
  888.     }
  889.  
  890.     while (!done)
  891.     {
  892.         for (j=0 ; (j<numlowresmodes) && (nummodes < MAX_MODE_LIST) ; j++)
  893.         {
  894.             devmode.dmBitsPerPel = bpp;
  895.             devmode.dmPelsWidth = lowresmodes[j].width;
  896.             devmode.dmPelsHeight = lowresmodes[j].height;
  897.             devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
  898.  
  899.             if (ChangeDisplaySettings (&devmode, CDS_TEST | CDS_FULLSCREEN) ==
  900.                     DISP_CHANGE_SUCCESSFUL)
  901.             {
  902.                     modelist[nummodes].type = MS_FULLDIB;
  903.                     modelist[nummodes].width = devmode.dmPelsWidth;
  904.                     modelist[nummodes].height = devmode.dmPelsHeight;
  905.                     modelist[nummodes].modenum = 0;
  906.                     modelist[nummodes].mode13 = 0;
  907.                     modelist[nummodes].stretched = 0;
  908.                     modelist[nummodes].halfscreen = 0;
  909.                     modelist[nummodes].dib = 1;
  910.                     modelist[nummodes].fullscreen = 1;
  911.                     modelist[nummodes].bpp = devmode.dmBitsPerPel;
  912.                     sprintf (modelist[nummodes].modedesc, "%dx%d",
  913.                              devmode.dmPelsWidth, devmode.dmPelsHeight);
  914.  
  915.             // we only want the lowest-bpp version of each mode
  916.                 for (i=originalnummodes, existingmode = 0 ; i<nummodes ; i++)
  917.                 {
  918.                     if ((modelist[nummodes].width == modelist[i].width)   &&
  919.                         (modelist[nummodes].height == modelist[i].height) &&
  920.                         (modelist[nummodes].bpp >= modelist[i].bpp))
  921.                     {
  922.                         existingmode = 1;
  923.                         break;
  924.                     }
  925.                 }
  926.  
  927.                 if (!existingmode)
  928.                 {
  929.                     if (modelist[nummodes].width < lowestres)
  930.                         lowestres = modelist[nummodes].width;
  931.  
  932.                     nummodes++;
  933.                 }
  934.             }
  935.         }
  936.  
  937.         switch (bpp)
  938.         {
  939.             case 8:
  940.                 bpp = 16;
  941.                 break;
  942.  
  943.             case 16:
  944.                 bpp = 32;
  945.                 break;
  946.  
  947.             case 32:
  948.                 done = 1;
  949.                 break;
  950.         }
  951.     }
  952.  
  953. // now add the lowest stretch-by-2 pseudo-modes between 320-wide
  954. // (inclusive) and lowest real res (not inclusive)
  955. // don't bother if we have a real VGA mode 0x13 mode
  956.     if (!is_mode0x13)
  957.     {
  958.         for (i=originalnummodes, cstretch=0 ; i<nummodes ; i++)
  959.         {
  960.             if (((modelist[i].width >> 1) < lowestres) &&
  961.                 ((modelist[i].width >> 1) >= 320))
  962.             {
  963.                 lowestres = modelist[i].width >> 1;
  964.                 cstretch = 1;
  965.                 mstretch = i;
  966.             }
  967.         }
  968.  
  969.         if ((nummodes + cstretch) > MAX_MODE_LIST)
  970.             cstretch = MAX_MODE_LIST - nummodes;
  971.  
  972.         if (cstretch > 0)
  973.         {
  974.             for (i=(nummodes-1) ; i>=originalnummodes ; i--)
  975.                 modelist[i+cstretch] = modelist[i];
  976.  
  977.             nummodes += cstretch;
  978.             istretch = originalnummodes;
  979.  
  980.             modelist[istretch] = modelist[mstretch];
  981.             modelist[istretch].width >>= 1;
  982.             modelist[istretch].height >>= 1;
  983.             modelist[istretch].stretched = 1;
  984.             sprintf (modelist[istretch].modedesc, "%dx%d",
  985.                      modelist[istretch].width, modelist[istretch].height);
  986.         }
  987.     }
  988.  
  989.     if (nummodes != originalnummodes)
  990.         vid_default = MODE_FULLSCREEN_DEFAULT;
  991.     else
  992.         Con_SafePrintf ("No fullscreen DIB modes found\n");
  993. }
  994.  
  995.  
  996. /*
  997. =================
  998. VID_NumModes
  999. =================
  1000. */
  1001. int VID_NumModes (void)
  1002. {
  1003.     return nummodes;
  1004. }
  1005.  
  1006.     
  1007. /*
  1008. =================
  1009. VID_GetModePtr
  1010. =================
  1011. */
  1012. vmode_t *VID_GetModePtr (int modenum)
  1013. {
  1014.  
  1015.     if ((modenum >= 0) && (modenum < nummodes))
  1016.         return &modelist[modenum];
  1017.     else
  1018.         return &badmode;
  1019. }
  1020.  
  1021.  
  1022. /*
  1023. =================
  1024. VID_CheckModedescFixup
  1025. =================
  1026. */
  1027. void VID_CheckModedescFixup (int mode)
  1028. {
  1029.     int        x, y, stretch;
  1030.  
  1031.     if (mode == MODE_SETTABLE_WINDOW)
  1032.     {
  1033.         modelist[mode].stretched = (int)vid_stretch_by_2.value;
  1034.         stretch = modelist[mode].stretched;
  1035.  
  1036.         if (vid_config_x.value < (320 << stretch))
  1037.             vid_config_x.value = 320 << stretch;
  1038.  
  1039.         if (vid_config_y.value < (200 << stretch))
  1040.             vid_config_y.value = 200 << stretch;
  1041.  
  1042.         x = (int)vid_config_x.value;
  1043.         y = (int)vid_config_y.value;
  1044.         sprintf (modelist[mode].modedesc, "%dx%d", x, y);
  1045.         modelist[mode].width = x;
  1046.         modelist[mode].height = y;
  1047.     }
  1048. }
  1049.  
  1050.  
  1051. /*
  1052. =================
  1053. VID_GetModeDescriptionMemCheck
  1054. =================
  1055. */
  1056. char *VID_GetModeDescriptionMemCheck (int mode)
  1057. {
  1058.     char        *pinfo;
  1059.     vmode_t        *pv;
  1060.  
  1061.     if ((mode < 0) || (mode >= nummodes))
  1062.         return NULL;
  1063.  
  1064.     VID_CheckModedescFixup (mode);
  1065.  
  1066.     pv = VID_GetModePtr (mode);
  1067.     pinfo = pv->modedesc;
  1068.  
  1069.     if (VID_CheckAdequateMem (pv->width, pv->height))
  1070.     {
  1071.         return pinfo;
  1072.     }
  1073.     else
  1074.     {
  1075.         return NULL;
  1076.     }
  1077. }
  1078.  
  1079.  
  1080. /*
  1081. =================
  1082. VID_GetModeDescription
  1083. =================
  1084. */
  1085. char *VID_GetModeDescription (int mode)
  1086. {
  1087.     char        *pinfo;
  1088.     vmode_t        *pv;
  1089.  
  1090.     if ((mode < 0) || (mode >= nummodes))
  1091.         return NULL;
  1092.  
  1093.     VID_CheckModedescFixup (mode);
  1094.  
  1095.     pv = VID_GetModePtr (mode);
  1096.     pinfo = pv->modedesc;
  1097.     return pinfo;
  1098. }
  1099.  
  1100.  
  1101. /*
  1102. =================
  1103. VID_GetModeDescription2
  1104.  
  1105. Tacks on "windowed" or "fullscreen"
  1106. =================
  1107. */
  1108. char *VID_GetModeDescription2 (int mode)
  1109. {
  1110.     static char    pinfo[40];
  1111.     vmode_t        *pv;
  1112.  
  1113.     if ((mode < 0) || (mode >= nummodes))
  1114.         return NULL;
  1115.  
  1116.     VID_CheckModedescFixup (mode);
  1117.  
  1118.     pv = VID_GetModePtr (mode);
  1119.  
  1120.     if (modelist[mode].type == MS_FULLSCREEN)
  1121.     {
  1122.         sprintf(pinfo,"%s fullscreen", pv->modedesc);
  1123.     }
  1124.     else if (modelist[mode].type == MS_FULLDIB)
  1125.     {
  1126.         sprintf(pinfo,"%s fullscreen", pv->modedesc);
  1127.     }
  1128.     else
  1129.     {
  1130.         sprintf(pinfo, "%s windowed", pv->modedesc);
  1131.     }
  1132.  
  1133.     return pinfo;
  1134. }
  1135.  
  1136.  
  1137. // KJB: Added this to return the mode driver name in description for console
  1138.  
  1139. char *VID_GetExtModeDescription (int mode)
  1140. {
  1141.     static char    pinfo[40];
  1142.     vmode_t        *pv;
  1143.  
  1144.     if ((mode < 0) || (mode >= nummodes))
  1145.         return NULL;
  1146.  
  1147.     VID_CheckModedescFixup (mode);
  1148.  
  1149.     pv = VID_GetModePtr (mode);
  1150.     if (modelist[mode].type == MS_FULLSCREEN)
  1151.     {
  1152.         sprintf(pinfo,"%s fullscreen %s",pv->modedesc,
  1153.                 MGL_modeDriverName(pv->modenum));
  1154.     }
  1155.     else if (modelist[mode].type == MS_FULLDIB)
  1156.     {
  1157.         sprintf(pinfo,"%s fullscreen DIB", pv->modedesc);
  1158.     }
  1159.     else
  1160.     {
  1161.         sprintf(pinfo, "%s windowed", pv->modedesc);
  1162.     }
  1163.  
  1164.     return pinfo;
  1165. }
  1166.  
  1167.  
  1168. void DestroyDIBWindow (void)
  1169. {
  1170.  
  1171.     if (modestate == MS_WINDOWED)
  1172.     {
  1173.     // destroy the associated MGL DC's; the window gets reused
  1174.         if (windc)
  1175.             MGL_destroyDC(windc);
  1176.         if (dibdc)
  1177.             MGL_destroyDC(dibdc);
  1178.         windc = dibdc = NULL;
  1179.     }
  1180. }
  1181.  
  1182.  
  1183. void DestroyFullscreenWindow (void)
  1184. {
  1185.  
  1186.     if (modestate == MS_FULLSCREEN)
  1187.     {
  1188.     // destroy the existing fullscreen mode and DC's
  1189.         if (mgldc)
  1190.             MGL_destroyDC (mgldc);
  1191.         if (memdc)
  1192.             MGL_destroyDC (memdc);
  1193.         mgldc = memdc = NULL;
  1194.     }
  1195. }
  1196.  
  1197.  
  1198.  
  1199. void DestroyFullDIBWindow (void)
  1200. {
  1201.     if (modestate == MS_FULLDIB)
  1202.     {
  1203.         ChangeDisplaySettings (NULL, CDS_FULLSCREEN);
  1204.  
  1205.     // Destroy the fullscreen DIB window and associated MGL DC's
  1206.         if (windc)
  1207.             MGL_destroyDC(windc);
  1208.         if (dibdc)
  1209.             MGL_destroyDC(dibdc);
  1210.         windc = dibdc = NULL;
  1211.     }
  1212. }
  1213.  
  1214.  
  1215. qboolean VID_SetWindowedMode (int modenum)
  1216. {
  1217.     HDC                hdc;
  1218.     pixel_format_t    pf;
  1219.     qboolean        stretched;
  1220.     int                lastmodestate;
  1221.     LONG            wlong;
  1222.  
  1223.     if (!windowed_mode_set)
  1224.     {
  1225.         if (COM_CheckParm ("-resetwinpos"))
  1226.         {
  1227.             Cvar_SetValue ("vid_window_x", 0.0);
  1228.             Cvar_SetValue ("vid_window_y", 0.0);
  1229.         }
  1230.  
  1231.         windowed_mode_set;
  1232.     }
  1233.  
  1234.     VID_CheckModedescFixup (modenum);
  1235.  
  1236.     DDActive = 0;
  1237.     lastmodestate = modestate;
  1238.  
  1239.     DestroyFullscreenWindow ();
  1240.     DestroyFullDIBWindow ();
  1241.  
  1242.     if (windc)
  1243.         MGL_destroyDC(windc);
  1244.     if (dibdc)
  1245.         MGL_destroyDC(dibdc);
  1246.     windc = dibdc = NULL;
  1247.  
  1248. // KJB: Signal to the MGL that we are going back to windowed mode
  1249.     if (!MGL_changeDisplayMode(grWINDOWED))
  1250.         initFatalError();
  1251.  
  1252.     WindowRect.top = WindowRect.left = 0;
  1253.  
  1254.     WindowRect.right = modelist[modenum].width;
  1255.     WindowRect.bottom = modelist[modenum].height;
  1256.     stretched = modelist[modenum].stretched;
  1257.  
  1258.     DIBWidth = modelist[modenum].width;
  1259.     DIBHeight = modelist[modenum].height;
  1260.  
  1261.     if (stretched)
  1262.     {
  1263.         DIBWidth >>= 1;
  1264.         DIBHeight >>= 1;
  1265.     }
  1266.  
  1267.     WindowStyle = WS_OVERLAPPED | WS_BORDER | WS_CAPTION | WS_SYSMENU |
  1268.                   WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPSIBLINGS |
  1269.                   WS_CLIPCHILDREN;
  1270.     ExWindowStyle = 0;
  1271.     AdjustWindowRectEx(&WindowRect, WindowStyle, FALSE, 0);
  1272.  
  1273. // the first time we're called to set the mode, create the window we'll use
  1274. // for the rest of the session
  1275.     if (!vid_mode_set)
  1276.     {
  1277.         mainwindow = CreateWindowEx (
  1278.              ExWindowStyle,
  1279.              "WinQuake",
  1280.              "WinQuake",
  1281.              WindowStyle,
  1282.              0, 0,
  1283.              WindowRect.right - WindowRect.left,
  1284.              WindowRect.bottom - WindowRect.top,
  1285.              NULL,
  1286.              NULL,
  1287.              global_hInstance,
  1288.              NULL);
  1289.  
  1290.         if (!mainwindow)
  1291.             Sys_Error ("Couldn't create DIB window");
  1292.  
  1293.     // tell MGL to use this window for fullscreen modes
  1294.         MGL_registerFullScreenWindow (mainwindow);
  1295.  
  1296.         vid_mode_set = true;
  1297.     }
  1298.     else
  1299.     {
  1300.         SetWindowLong(mainwindow, GWL_STYLE, WindowStyle | WS_VISIBLE);
  1301.         SetWindowLong(mainwindow, GWL_EXSTYLE, ExWindowStyle);
  1302.     }
  1303.  
  1304.     if (!SetWindowPos (mainwindow,
  1305.                        NULL,
  1306.                        0, 0,
  1307.                        WindowRect.right - WindowRect.left,
  1308.                        WindowRect.bottom - WindowRect.top,
  1309.                        SWP_NOCOPYBITS | SWP_NOZORDER |
  1310.                         SWP_HIDEWINDOW))
  1311.     {
  1312.         Sys_Error ("Couldn't resize DIB window");
  1313.     }
  1314.  
  1315.     if (hide_window)
  1316.         return true;
  1317.  
  1318. // position and show the DIB window
  1319.     VID_CheckWindowXY ();
  1320.     SetWindowPos (mainwindow, NULL, (int)vid_window_x.value,
  1321.                   (int)vid_window_y.value, 0, 0,
  1322.                   SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW | SWP_DRAWFRAME);
  1323.  
  1324.     if (force_minimized)
  1325.         ShowWindow (mainwindow, SW_MINIMIZE);
  1326.     else
  1327.         ShowWindow (mainwindow, SW_SHOWDEFAULT);
  1328.  
  1329.     UpdateWindow (mainwindow);
  1330.  
  1331.     modestate = MS_WINDOWED;
  1332.     vid_fulldib_on_focus_mode = 0;
  1333.  
  1334. // because we have set the background brush for the window to NULL
  1335. // (to avoid flickering when re-sizing the window on the desktop),
  1336. // we clear the window to black when created, otherwise it will be
  1337. // empty while Quake starts up.
  1338.     hdc = GetDC(mainwindow);
  1339.     PatBlt(hdc,0,0,WindowRect.right,WindowRect.bottom,BLACKNESS);
  1340.     ReleaseDC(mainwindow, hdc);
  1341.  
  1342.     /* Create the MGL window DC and the MGL memory DC */
  1343.     if ((windc = MGL_createWindowedDC(mainwindow)) == NULL)
  1344.         MGL_fatalError("Unable to create Windowed DC!");
  1345.  
  1346.     if ((dibdc = MGL_createMemoryDC(DIBWidth,DIBHeight,8,&pf)) == NULL)
  1347.         MGL_fatalError("Unable to create Memory DC!");
  1348.  
  1349.     MGL_makeCurrentDC(dibdc);
  1350.  
  1351.     vid.buffer = vid.conbuffer = vid.direct = dibdc->surface;
  1352.     vid.rowbytes = vid.conrowbytes = dibdc->mi.bytesPerLine;
  1353.     vid.numpages = 1;
  1354.     vid.maxwarpwidth = WARP_WIDTH;
  1355.     vid.maxwarpheight = WARP_HEIGHT;
  1356.     vid.height = vid.conheight = DIBHeight;
  1357.     vid.width = vid.conwidth = DIBWidth;
  1358.     vid.aspect = ((float)vid.height / (float)vid.width) *
  1359.                 (320.0 / 240.0);
  1360.  
  1361.     vid_stretched = stretched;
  1362.  
  1363.     SendMessage (mainwindow, WM_SETICON, (WPARAM)TRUE, (LPARAM)hIcon);
  1364.     SendMessage (mainwindow, WM_SETICON, (WPARAM)FALSE, (LPARAM)hIcon);
  1365.  
  1366.     return true;
  1367. }
  1368.  
  1369.  
  1370. qboolean VID_SetFullscreenMode (int modenum)
  1371. {
  1372.  
  1373.     DDActive = 1;
  1374.  
  1375.     DestroyDIBWindow ();
  1376.     DestroyFullDIBWindow ();
  1377.  
  1378.     mode = modelist[modenum].modenum;
  1379.  
  1380.     // Destroy old DC's, resetting back to fullscreen mode
  1381.     if (mgldc)
  1382.         MGL_destroyDC (mgldc);
  1383.     if (memdc)
  1384.         MGL_destroyDC (memdc);
  1385.     mgldc = memdc = NULL;
  1386.  
  1387.     if ((mgldc = createDisplayDC (modelist[modenum].stretched ||
  1388.          (int)vid_nopageflip.value)) == NULL)
  1389.     {
  1390.         return false;
  1391.     }
  1392.  
  1393.     modestate = MS_FULLSCREEN;
  1394.     vid_fulldib_on_focus_mode = 0;
  1395.  
  1396.     vid.buffer = vid.conbuffer = vid.direct = NULL;
  1397.     vid.maxwarpwidth = WARP_WIDTH;
  1398.     vid.maxwarpheight = WARP_HEIGHT;
  1399.     DIBHeight = vid.height = vid.conheight = modelist[modenum].height;
  1400.     DIBWidth = vid.width = vid.conwidth = modelist[modenum].width;
  1401.     vid.aspect = ((float)vid.height / (float)vid.width) *
  1402.                 (320.0 / 240.0);
  1403.  
  1404.     vid_stretched = modelist[modenum].stretched;
  1405.  
  1406. // needed because we're not getting WM_MOVE messages fullscreen on NT
  1407.     window_x = 0;
  1408.     window_y = 0;
  1409.  
  1410. // set the large icon, so the Quake icon will show up in the taskbar
  1411.     SendMessage (mainwindow, WM_SETICON, (WPARAM)1, (LPARAM)hIcon);
  1412.     SendMessage (mainwindow, WM_SETICON, (WPARAM)0, (LPARAM)hIcon);
  1413.  
  1414. // shouldn't be needed, but Kendall needs to let us get the activation
  1415. // message for this not to be needed on NT
  1416.     AppActivate (true, false);
  1417.  
  1418.     return true;
  1419. }
  1420.  
  1421.  
  1422. qboolean VID_SetFullDIBMode (int modenum)
  1423. {
  1424.     HDC                hdc;
  1425.     pixel_format_t    pf;
  1426.     int                lastmodestate;
  1427.  
  1428.     DDActive = 0;
  1429.  
  1430.     DestroyFullscreenWindow ();
  1431.     DestroyDIBWindow ();
  1432.  
  1433.     if (windc)
  1434.         MGL_destroyDC(windc);
  1435.     if (dibdc)
  1436.         MGL_destroyDC(dibdc);
  1437.     windc = dibdc = NULL;
  1438.  
  1439. // KJB: Signal to the MGL that we are going back to windowed mode
  1440.     if (!MGL_changeDisplayMode(grWINDOWED))
  1441.         initFatalError();
  1442.  
  1443.     gdevmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
  1444.     gdevmode.dmBitsPerPel = modelist[modenum].bpp;
  1445.     gdevmode.dmPelsWidth = modelist[modenum].width << modelist[modenum].stretched <<
  1446.                            modelist[modenum].halfscreen;
  1447.     gdevmode.dmPelsHeight = modelist[modenum].height << modelist[modenum].stretched;
  1448.     gdevmode.dmSize = sizeof (gdevmode);
  1449.  
  1450.     if (ChangeDisplaySettings (&gdevmode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
  1451.         Sys_Error ("Couldn't set fullscreen DIB mode");
  1452.  
  1453.     lastmodestate = modestate;
  1454.     modestate = MS_FULLDIB;
  1455.     vid_fulldib_on_focus_mode = modenum;
  1456.  
  1457.     WindowRect.top = WindowRect.left = 0;
  1458.  
  1459.     hdc = GetDC(NULL);
  1460.  
  1461.     WindowRect.right = modelist[modenum].width << modelist[modenum].stretched;
  1462.     WindowRect.bottom = modelist[modenum].height << modelist[modenum].stretched;
  1463.  
  1464.     ReleaseDC(NULL,hdc);
  1465.  
  1466.     DIBWidth = modelist[modenum].width;
  1467.     DIBHeight = modelist[modenum].height;
  1468.  
  1469.     WindowStyle = WS_POPUP | WS_SYSMENU | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
  1470.     ExWindowStyle = 0;
  1471.     AdjustWindowRectEx(&WindowRect, WindowStyle, FALSE, 0);
  1472.  
  1473.     SetWindowLong(mainwindow, GWL_STYLE, WindowStyle | WS_VISIBLE);
  1474.     SetWindowLong(mainwindow, GWL_EXSTYLE, ExWindowStyle);
  1475.  
  1476.     if (!SetWindowPos (mainwindow,
  1477.                        NULL,
  1478.                        0, 0,
  1479.                        WindowRect.right - WindowRect.left,
  1480.                        WindowRect.bottom - WindowRect.top,
  1481.                        SWP_NOCOPYBITS | SWP_NOZORDER))
  1482.     {
  1483.         Sys_Error ("Couldn't resize DIB window");
  1484.     }
  1485.  
  1486. // position and show the DIB window
  1487.     SetWindowPos (mainwindow, HWND_TOPMOST, 0, 0, 0, 0,
  1488.                   SWP_NOSIZE | SWP_SHOWWINDOW | SWP_DRAWFRAME);
  1489.     ShowWindow (mainwindow, SW_SHOWDEFAULT);
  1490.     UpdateWindow (mainwindow);
  1491.  
  1492.     // Because we have set the background brush for the window to NULL
  1493.     // (to avoid flickering when re-sizing the window on the desktop), we
  1494.     // clear the window to black when created, otherwise it will be
  1495.     // empty while Quake starts up.
  1496.     hdc = GetDC(mainwindow);
  1497.     PatBlt(hdc,0,0,WindowRect.right,WindowRect.bottom,BLACKNESS);
  1498.     ReleaseDC(mainwindow, hdc);
  1499.  
  1500.     /* Create the MGL window DC and the MGL memory DC */
  1501.     if ((windc = MGL_createWindowedDC(mainwindow)) == NULL)
  1502.         MGL_fatalError("Unable to create Fullscreen DIB DC!");
  1503.  
  1504.     if ((dibdc = MGL_createMemoryDC(DIBWidth,DIBHeight,8,&pf)) == NULL)
  1505.         MGL_fatalError("Unable to create Memory DC!");
  1506.  
  1507.     MGL_makeCurrentDC(dibdc);
  1508.  
  1509.     vid.buffer = vid.conbuffer = vid.direct = dibdc->surface;
  1510.     vid.rowbytes = vid.conrowbytes = dibdc->mi.bytesPerLine;
  1511.     vid.numpages = 1;
  1512.     vid.maxwarpwidth = WARP_WIDTH;
  1513.     vid.maxwarpheight = WARP_HEIGHT;
  1514.     vid.height = vid.conheight = DIBHeight;
  1515.     vid.width = vid.conwidth = DIBWidth;
  1516.     vid.aspect = ((float)vid.height / (float)vid.width) *
  1517.                 (320.0 / 240.0);
  1518.  
  1519.     vid_stretched = modelist[modenum].stretched;
  1520.  
  1521. // needed because we're not getting WM_MOVE messages fullscreen on NT
  1522.     window_x = 0;
  1523.     window_y = 0;
  1524.  
  1525.     return true;
  1526. }
  1527.  
  1528.  
  1529. void VID_RestoreOldMode (int original_mode)
  1530. {
  1531.     static qboolean    inerror = false;
  1532.  
  1533.     if (inerror)
  1534.         return;
  1535.  
  1536.     in_mode_set = false;
  1537.     inerror = true;
  1538.  
  1539. // make sure mode set happens (video mode changes)
  1540.     vid_modenum = original_mode - 1;
  1541.  
  1542.     if (!VID_SetMode (original_mode, vid_curpal))
  1543.     {
  1544.         vid_modenum = MODE_WINDOWED - 1;
  1545.  
  1546.         if (!VID_SetMode (windowed_default, vid_curpal))
  1547.             Sys_Error ("Can't set any video mode");
  1548.     }
  1549.  
  1550.     inerror = false;
  1551. }
  1552.  
  1553.  
  1554. void VID_SetDefaultMode (void)
  1555. {
  1556.  
  1557.     if (vid_initialized)
  1558.         VID_SetMode (0, vid_curpal);
  1559.  
  1560.     IN_DeactivateMouse ();
  1561. }
  1562.  
  1563.  
  1564. int VID_SetMode (int modenum, unsigned char *palette)
  1565. {
  1566.     int                original_mode, temp, dummy;
  1567.     qboolean        stat;
  1568.     MSG                msg;
  1569.     HDC                hdc;
  1570.  
  1571.     while ((modenum >= nummodes) || (modenum < 0))
  1572.     {
  1573.         if (vid_modenum == NO_MODE)
  1574.         {
  1575.             if (modenum == vid_default)
  1576.             {
  1577.                 modenum = windowed_default;
  1578.             }
  1579.             else
  1580.             {
  1581.                 modenum = vid_default;
  1582.             }
  1583.  
  1584.             Cvar_SetValue ("vid_mode", (float)modenum);
  1585.         }
  1586.         else
  1587.         {
  1588.             Cvar_SetValue ("vid_mode", (float)vid_modenum);
  1589.             return 0;
  1590.         }
  1591.     }
  1592.  
  1593.     if (!force_mode_set && (modenum == vid_modenum))
  1594.         return true;
  1595.  
  1596. // so Con_Printfs don't mess us up by forcing vid and snd updates
  1597.     temp = scr_disabled_for_loading;
  1598.     scr_disabled_for_loading = true;
  1599.     in_mode_set = true;
  1600.  
  1601.     CDAudio_Pause ();
  1602.     S_ClearBuffer ();
  1603.  
  1604.     if (vid_modenum == NO_MODE)
  1605.         original_mode = windowed_default;
  1606.     else
  1607.         original_mode = vid_modenum;
  1608.  
  1609.     // Set either the fullscreen or windowed mode
  1610.     if (modelist[modenum].type == MS_WINDOWED)
  1611.     {
  1612.         if (_windowed_mouse.value)
  1613.         {
  1614.             stat = VID_SetWindowedMode(modenum);
  1615.             IN_ActivateMouse ();
  1616.             IN_HideMouse ();
  1617.         }
  1618.         else
  1619.         {
  1620.             IN_DeactivateMouse ();
  1621.             IN_ShowMouse ();
  1622.             stat = VID_SetWindowedMode(modenum);
  1623.         }
  1624.     }
  1625.     else if (modelist[modenum].type == MS_FULLDIB)
  1626.     {
  1627.         stat = VID_SetFullDIBMode(modenum);
  1628.         IN_ActivateMouse ();
  1629.         IN_HideMouse ();
  1630.     }
  1631.     else
  1632.     {
  1633.         stat = VID_SetFullscreenMode(modenum);
  1634.         IN_ActivateMouse ();
  1635.         IN_HideMouse ();
  1636.     }
  1637.  
  1638.     window_width = vid.width << vid_stretched;
  1639.     window_height = vid.height << vid_stretched;
  1640.     VID_UpdateWindowStatus ();
  1641.  
  1642.     CDAudio_Resume ();
  1643.     scr_disabled_for_loading = temp;
  1644.  
  1645.     if (!stat)
  1646.     {
  1647.         VID_RestoreOldMode (original_mode);
  1648.         return false;
  1649.     }
  1650.  
  1651.     if (hide_window)
  1652.         return true;
  1653.  
  1654. // now we try to make sure we get the focus on the mode switch, because
  1655. // sometimes in some systems we don't.  We grab the foreground, then
  1656. // finish setting up, pump all our messages, and sleep for a little while
  1657. // to let messages finish bouncing around the system, then we put
  1658. // ourselves at the top of the z order, then grab the foreground again,
  1659. // Who knows if it helps, but it probably doesn't hurt
  1660.     if (!force_minimized)
  1661.         SetForegroundWindow (mainwindow);
  1662.  
  1663.     hdc = GetDC(NULL);
  1664.  
  1665.     if (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE)
  1666.         vid_palettized = true;
  1667.     else
  1668.         vid_palettized = false;
  1669.  
  1670.     VID_SetPalette (palette);
  1671.  
  1672.     ReleaseDC(NULL,hdc);
  1673.  
  1674.     vid_modenum = modenum;
  1675.     Cvar_SetValue ("vid_mode", (float)vid_modenum);
  1676.  
  1677.     if (!VID_AllocBuffers (vid.width, vid.height))
  1678.     {
  1679.     // couldn't get memory for this mode; try to fall back to previous mode
  1680.         VID_RestoreOldMode (original_mode);
  1681.         return false;
  1682.     }
  1683.  
  1684.     D_InitCaches (vid_surfcache, vid_surfcachesize);
  1685.  
  1686.     while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
  1687.     {
  1688.           TranslateMessage (&msg);
  1689.           DispatchMessage (&msg);
  1690.     }
  1691.  
  1692.     Sleep (100);
  1693.  
  1694.     if (!force_minimized)
  1695.     {
  1696.         SetWindowPos (mainwindow, HWND_TOP, 0, 0, 0, 0,
  1697.                   SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW |
  1698.                   SWP_NOCOPYBITS);
  1699.  
  1700.         SetForegroundWindow (mainwindow);
  1701.     }
  1702.  
  1703. // fix the leftover Alt from any Alt-Tab or the like that switched us away
  1704.     ClearAllStates ();
  1705.  
  1706.     if (!msg_suppress_1)
  1707.         Con_SafePrintf ("%s\n", VID_GetModeDescription (vid_modenum));
  1708.  
  1709.     VID_SetPalette (palette);
  1710.  
  1711.     in_mode_set = false;
  1712.     vid.recalc_refdef = 1;
  1713.  
  1714.     return true;
  1715. }
  1716.  
  1717. void VID_LockBuffer (void)
  1718. {
  1719.  
  1720.     if (dibdc)
  1721.         return;
  1722.  
  1723.     lockcount++;
  1724.  
  1725.     if (lockcount > 1)
  1726.         return;
  1727.  
  1728.     MGL_beginDirectAccess();
  1729.  
  1730.     if (memdc)
  1731.     {
  1732.         // Update surface pointer for linear access modes
  1733.         vid.buffer = vid.conbuffer = vid.direct = memdc->surface;
  1734.         vid.rowbytes = vid.conrowbytes = memdc->mi.bytesPerLine;
  1735.     }
  1736.     else if (mgldc)
  1737.     {
  1738.         // Update surface pointer for linear access modes
  1739.         vid.buffer = vid.conbuffer = vid.direct = mgldc->surface;
  1740.         vid.rowbytes = vid.conrowbytes = mgldc->mi.bytesPerLine;
  1741.     }
  1742.  
  1743.     if (r_dowarp)
  1744.         d_viewbuffer = r_warpbuffer;
  1745.     else
  1746.         d_viewbuffer = (void *)(byte *)vid.buffer;
  1747.  
  1748.     if (r_dowarp)
  1749.         screenwidth = WARP_WIDTH;
  1750.     else
  1751.         screenwidth = vid.rowbytes;
  1752.  
  1753.     if (lcd_x.value)
  1754.         screenwidth <<= 1;
  1755. }
  1756.         
  1757.         
  1758. void VID_UnlockBuffer (void)
  1759. {
  1760.     if (dibdc)
  1761.         return;
  1762.  
  1763.     lockcount--;
  1764.  
  1765.     if (lockcount > 0)
  1766.         return;
  1767.  
  1768.     if (lockcount < 0)
  1769.         Sys_Error ("Unbalanced unlock");
  1770.  
  1771.     MGL_endDirectAccess();
  1772.  
  1773. // to turn up any unlocked accesses
  1774.     vid.buffer = vid.conbuffer = vid.direct = d_viewbuffer = NULL;
  1775.  
  1776. }
  1777.  
  1778.  
  1779. int VID_ForceUnlockedAndReturnState (void)
  1780. {
  1781.     int    lk;
  1782.  
  1783.     if (!lockcount)
  1784.         return 0;
  1785.  
  1786.     lk = lockcount;
  1787.  
  1788.     if (dibdc)
  1789.     {
  1790.         lockcount = 0;
  1791.     }
  1792.     else
  1793.     {
  1794.         lockcount = 1;
  1795.         VID_UnlockBuffer ();
  1796.     }
  1797.  
  1798.     return lk;
  1799. }
  1800.  
  1801.  
  1802. void VID_ForceLockState (int lk)
  1803. {
  1804.  
  1805.     if (!dibdc && lk)
  1806.     {
  1807.         lockcount = 0;
  1808.         VID_LockBuffer ();
  1809.     }
  1810.  
  1811.     lockcount = lk;
  1812. }
  1813.  
  1814.  
  1815. void    VID_SetPalette (unsigned char *palette)
  1816. {
  1817.     INT            i;
  1818.     palette_t    pal[256];
  1819.     HDC            hdc;
  1820.  
  1821.     if (!Minimized)
  1822.     {
  1823.         palette_changed = true;
  1824.  
  1825.     // make sure we have the static colors if we're the active app
  1826.         hdc = GetDC(NULL);
  1827.  
  1828.         if (vid_palettized && ActiveApp)
  1829.         {
  1830.             if (GetSystemPaletteUse(hdc) == SYSPAL_STATIC)
  1831.             {
  1832.             // switch to SYSPAL_NOSTATIC and remap the colors
  1833.                 SetSystemPaletteUse(hdc, SYSPAL_NOSTATIC);
  1834.                 syscolchg = true;
  1835.                 pal_is_nostatic = true;
  1836.             }
  1837.         }
  1838.  
  1839.         ReleaseDC(NULL,hdc);
  1840.  
  1841.         // Translate the palette values to an MGL palette array and
  1842.         // set the values.
  1843.         for (i = 0; i < 256; i++)
  1844.         {
  1845.             pal[i].red = palette[i*3];
  1846.             pal[i].green = palette[i*3+1];
  1847.             pal[i].blue = palette[i*3+2];
  1848.         }
  1849.  
  1850.         if (DDActive)
  1851.         {
  1852.             if (!mgldc)
  1853.                 return;
  1854.  
  1855.             MGL_setPalette(mgldc,pal,256,0);
  1856.             MGL_realizePalette(mgldc,256,0,false);
  1857.             if (memdc)
  1858.                 MGL_setPalette(memdc,pal,256,0);
  1859.         }
  1860.         else
  1861.         {
  1862.             if (!windc)
  1863.                 return;
  1864.  
  1865.             MGL_setPalette(windc,pal,256,0);
  1866.             MGL_realizePalette(windc,256,0,false);
  1867.             if (dibdc)
  1868.             {
  1869.                 MGL_setPalette(dibdc,pal,256,0);
  1870.                 MGL_realizePalette(dibdc,256,0,false);
  1871.             }
  1872.         }
  1873.     }
  1874.  
  1875.     memcpy (vid_curpal, palette, sizeof(vid_curpal));
  1876.  
  1877.     if (syscolchg)
  1878.     {
  1879.         PostMessage (HWND_BROADCAST, WM_SYSCOLORCHANGE, (WPARAM)0, (LPARAM)0);
  1880.         syscolchg = false;
  1881.     }
  1882. }
  1883.  
  1884.  
  1885. void    VID_ShiftPalette (unsigned char *palette)
  1886. {
  1887.     VID_SetPalette (palette);
  1888. }
  1889.  
  1890.  
  1891. /*
  1892. =================
  1893. VID_DescribeCurrentMode_f
  1894. =================
  1895. */
  1896. void VID_DescribeCurrentMode_f (void)
  1897. {
  1898.     Con_Printf ("%s\n", VID_GetExtModeDescription (vid_modenum));
  1899. }
  1900.  
  1901.  
  1902. /*
  1903. =================
  1904. VID_NumModes_f
  1905. =================
  1906. */
  1907. void VID_NumModes_f (void)
  1908. {
  1909.  
  1910.     if (nummodes == 1)
  1911.         Con_Printf ("%d video mode is available\n", nummodes);
  1912.     else
  1913.         Con_Printf ("%d video modes are available\n", nummodes);
  1914. }
  1915.  
  1916.  
  1917. /*
  1918. =================
  1919. VID_DescribeMode_f
  1920. =================
  1921. */
  1922. void VID_DescribeMode_f (void)
  1923. {
  1924.     int        modenum;
  1925.     
  1926.     modenum = Q_atoi (Cmd_Argv(1));
  1927.  
  1928.     Con_Printf ("%s\n", VID_GetExtModeDescription (modenum));
  1929. }
  1930.  
  1931.  
  1932. /*
  1933. =================
  1934. VID_DescribeModes_f
  1935. =================
  1936. */
  1937. void VID_DescribeModes_f (void)
  1938. {
  1939.     int            i, lnummodes;
  1940.     char        *pinfo;
  1941.     qboolean    na;
  1942.     vmode_t        *pv;
  1943.  
  1944.     na = false;
  1945.  
  1946.     lnummodes = VID_NumModes ();
  1947.  
  1948.     for (i=0 ; i<lnummodes ; i++)
  1949.     {
  1950.         pv = VID_GetModePtr (i);
  1951.         pinfo = VID_GetExtModeDescription (i);
  1952.  
  1953.         if (VID_CheckAdequateMem (pv->width, pv->height))
  1954.         {
  1955.             Con_Printf ("%2d: %s\n", i, pinfo);
  1956.         }
  1957.         else
  1958.         {
  1959.             Con_Printf ("**: %s\n", pinfo);
  1960.             na = true;
  1961.         }
  1962.     }
  1963.  
  1964.     if (na)
  1965.     {
  1966.         Con_Printf ("\n[**: not enough system RAM for mode]\n");
  1967.     }
  1968. }
  1969.  
  1970.  
  1971. /*
  1972. =================
  1973. VID_TestMode_f
  1974. =================
  1975. */
  1976. void VID_TestMode_f (void)
  1977. {
  1978.     int        modenum;
  1979.     double    testduration;
  1980.  
  1981.     if (!vid_testingmode)
  1982.     {
  1983.         modenum = Q_atoi (Cmd_Argv(1));
  1984.  
  1985.         if (VID_SetMode (modenum, vid_curpal))
  1986.         {
  1987.             vid_testingmode = 1;
  1988.             testduration = Q_atof (Cmd_Argv(2));
  1989.             if (testduration == 0)
  1990.                 testduration = 5.0;
  1991.             vid_testendtime = realtime + testduration;
  1992.         }
  1993.     }
  1994. }
  1995.  
  1996.  
  1997. /*
  1998. =================
  1999. VID_Windowed_f
  2000. =================
  2001. */
  2002. void VID_Windowed_f (void)
  2003. {
  2004.  
  2005.     VID_SetMode ((int)vid_windowed_mode.value, vid_curpal);
  2006. }
  2007.  
  2008.  
  2009. /*
  2010. =================
  2011. VID_Fullscreen_f
  2012. =================
  2013. */
  2014. void VID_Fullscreen_f (void)
  2015. {
  2016.  
  2017.     VID_SetMode ((int)vid_fullscreen_mode.value, vid_curpal);
  2018. }
  2019.  
  2020.  
  2021. /*
  2022. =================
  2023. VID_Minimize_f
  2024. =================
  2025. */
  2026. void VID_Minimize_f (void)
  2027. {
  2028.  
  2029. // we only support minimizing windows; if you're fullscreen,
  2030. // switch to windowed first
  2031.     if (modestate == MS_WINDOWED)
  2032.         ShowWindow (mainwindow, SW_MINIMIZE);
  2033. }
  2034.  
  2035.  
  2036.  
  2037. /*
  2038. =================
  2039. VID_ForceMode_f
  2040. =================
  2041. */
  2042. void VID_ForceMode_f (void)
  2043. {
  2044.     int        modenum;
  2045.     double    testduration;
  2046.  
  2047.     if (!vid_testingmode)
  2048.     {
  2049.         modenum = Q_atoi (Cmd_Argv(1));
  2050.  
  2051.         force_mode_set = 1;
  2052.         VID_SetMode (modenum, vid_curpal);
  2053.         force_mode_set = 0;
  2054.     }
  2055. }
  2056.  
  2057.  
  2058. void    VID_Init (unsigned char *palette)
  2059. {
  2060.     int        i, bestmatch, bestmatchmetric, t, dr, dg, db;
  2061.     int        basenummodes;
  2062.     byte    *ptmp;
  2063.  
  2064.     Cvar_RegisterVariable (&vid_mode);
  2065.     Cvar_RegisterVariable (&vid_wait);
  2066.     Cvar_RegisterVariable (&vid_nopageflip);
  2067.     Cvar_RegisterVariable (&_vid_wait_override);
  2068.     Cvar_RegisterVariable (&_vid_default_mode);
  2069.     Cvar_RegisterVariable (&_vid_default_mode_win);
  2070.     Cvar_RegisterVariable (&vid_config_x);
  2071.     Cvar_RegisterVariable (&vid_config_y);
  2072.     Cvar_RegisterVariable (&vid_stretch_by_2);
  2073.     Cvar_RegisterVariable (&_windowed_mouse);
  2074.     Cvar_RegisterVariable (&vid_fullscreen_mode);
  2075.     Cvar_RegisterVariable (&vid_windowed_mode);
  2076.     Cvar_RegisterVariable (&block_switch);
  2077.     Cvar_RegisterVariable (&vid_window_x);
  2078.     Cvar_RegisterVariable (&vid_window_y);
  2079.  
  2080.     Cmd_AddCommand ("vid_testmode", VID_TestMode_f);
  2081.     Cmd_AddCommand ("vid_nummodes", VID_NumModes_f);
  2082.     Cmd_AddCommand ("vid_describecurrentmode", VID_DescribeCurrentMode_f);
  2083.     Cmd_AddCommand ("vid_describemode", VID_DescribeMode_f);
  2084.     Cmd_AddCommand ("vid_describemodes", VID_DescribeModes_f);
  2085.     Cmd_AddCommand ("vid_forcemode", VID_ForceMode_f);
  2086.     Cmd_AddCommand ("vid_windowed", VID_Windowed_f);
  2087.     Cmd_AddCommand ("vid_fullscreen", VID_Fullscreen_f);
  2088.     Cmd_AddCommand ("vid_minimize", VID_Minimize_f);
  2089.  
  2090.     if (COM_CheckParm ("-dibonly"))
  2091.         dibonly = true;
  2092.  
  2093.     VID_InitMGLDIB (global_hInstance);
  2094.  
  2095.     basenummodes = nummodes;
  2096.  
  2097.     if (!dibonly)
  2098.         VID_InitMGLFull (global_hInstance);
  2099.  
  2100. // if there are no non-windowed modes, or only windowed and mode 0x13, then use
  2101. // fullscreen DIBs as well
  2102.     if (((nummodes == basenummodes) ||
  2103.          ((nummodes == (basenummodes + 1)) && is_mode0x13)) &&
  2104.         !COM_CheckParm ("-nofulldib"))
  2105.  
  2106.     {
  2107.         VID_InitFullDIB (global_hInstance);
  2108.     }
  2109.  
  2110.     vid.maxwarpwidth = WARP_WIDTH;
  2111.     vid.maxwarpheight = WARP_HEIGHT;
  2112.     vid.colormap = host_colormap;
  2113.     vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048));
  2114.     vid_testingmode = 0;
  2115.  
  2116. // GDI doesn't let us remap palette index 0, so we'll remap color
  2117. // mappings from that black to another one
  2118.     bestmatchmetric = 256*256*3;
  2119.  
  2120.     for (i=1 ; i<256 ; i++)
  2121.     {
  2122.         dr = palette[0] - palette[i*3];
  2123.         dg = palette[1] - palette[i*3+1];
  2124.         db = palette[2] - palette[i*3+2];
  2125.  
  2126.         t = (dr * dr) + (dg * dg) + (db * db);
  2127.  
  2128.         if (t < bestmatchmetric)
  2129.         {
  2130.             bestmatchmetric = t;
  2131.             bestmatch = i;
  2132.  
  2133.             if (t == 0)
  2134.                 break;
  2135.         }
  2136.     }
  2137.  
  2138.     for (i=0, ptmp = vid.colormap ; i<(1<<(VID_CBITS+8)) ; i++, ptmp++)
  2139.     {
  2140.         if (*ptmp == 0)
  2141.             *ptmp = bestmatch;
  2142.     }
  2143.  
  2144.     if (COM_CheckParm("-startwindowed"))
  2145.     {
  2146.         startwindowed = 1;
  2147.         vid_default = windowed_default;
  2148.     }
  2149.  
  2150.     if (hwnd_dialog)
  2151.         DestroyWindow (hwnd_dialog);
  2152.  
  2153. // sound initialization has to go here, preceded by a windowed mode set,
  2154. // so there's a window for DirectSound to work with but we're not yet
  2155. // fullscreen so the "hardware already in use" dialog is visible if it
  2156. // gets displayed
  2157.  
  2158. // keep the window minimized until we're ready for the first real mode set
  2159.     hide_window = true;
  2160.     VID_SetMode (MODE_WINDOWED, palette);
  2161.     hide_window = false;
  2162.     S_Init ();
  2163.  
  2164.     vid_initialized = true;
  2165.  
  2166.     force_mode_set = true;
  2167.     VID_SetMode (vid_default, palette);
  2168.     force_mode_set = false;
  2169.  
  2170.     vid_realmode = vid_modenum;
  2171.  
  2172.     VID_SetPalette (palette);
  2173.  
  2174.     vid_menudrawfn = VID_MenuDraw;
  2175.     vid_menukeyfn = VID_MenuKey;
  2176.  
  2177.     strcpy (badmode.modedesc, "Bad mode");
  2178. }
  2179.  
  2180.  
  2181. void    VID_Shutdown (void)
  2182. {
  2183.     HDC                hdc;
  2184.     int                dummy;
  2185.  
  2186.     if (vid_initialized)
  2187.     {
  2188.         if (modestate == MS_FULLDIB)
  2189.             ChangeDisplaySettings (NULL, CDS_FULLSCREEN);
  2190.  
  2191.         PostMessage (HWND_BROADCAST, WM_PALETTECHANGED, (WPARAM)mainwindow, (LPARAM)0);
  2192.         PostMessage (HWND_BROADCAST, WM_SYSCOLORCHANGE, (WPARAM)0, (LPARAM)0);
  2193.  
  2194.         AppActivate(false, false);
  2195.         DestroyDIBWindow ();
  2196.         DestroyFullscreenWindow ();
  2197.         DestroyFullDIBWindow ();
  2198.  
  2199.         if (hwnd_dialog)
  2200.             DestroyWindow (hwnd_dialog);
  2201.  
  2202.         if (mainwindow)
  2203.             DestroyWindow(mainwindow);
  2204.  
  2205.         MGL_exit();
  2206.  
  2207.         vid_testingmode = 0;
  2208.         vid_initialized = 0;
  2209.     }
  2210. }
  2211.  
  2212.  
  2213. /*
  2214. ================
  2215. FlipScreen
  2216. ================
  2217. */
  2218. void FlipScreen(vrect_t *rects)
  2219. {
  2220.     HRESULT        ddrval;
  2221.  
  2222.     // Flip the surfaces
  2223.  
  2224.     if (DDActive)
  2225.     {
  2226.         if (mgldc)
  2227.         {
  2228.             if (memdc)
  2229.             {
  2230.                 while (rects)
  2231.                 {
  2232.                     if (vid_stretched)
  2233.                     {
  2234.                         MGL_stretchBltCoord(mgldc, memdc,
  2235.                                     rects->x,
  2236.                                     rects->y,
  2237.                                     rects->x + rects->width,
  2238.                                     rects->y + rects->height,
  2239.                                     rects->x << 1,
  2240.                                     rects->y << 1,
  2241.                                     (rects->x + rects->width) << 1,
  2242.                                     (rects->y + rects->height) << 1);
  2243.                     }
  2244.                     else
  2245.                     {
  2246.                         MGL_bitBltCoord(mgldc, memdc,
  2247.                                     rects->x, rects->y,
  2248.                                     (rects->x + rects->width),
  2249.                                     (rects->y + rects->height),
  2250.                                     rects->x, rects->y, MGL_REPLACE_MODE);
  2251.                     }
  2252.  
  2253.                     rects = rects->pnext;
  2254.                 }
  2255.             }
  2256.  
  2257.             if (vid.numpages > 1)
  2258.             {
  2259.                 // We have a flipping surface, so do a hard page flip
  2260.                 aPage = (aPage+1) % vid.numpages;
  2261.                 vPage = (vPage+1) % vid.numpages;
  2262.                 MGL_setActivePage(mgldc,aPage);
  2263.                 MGL_setVisualPage(mgldc,vPage,waitVRT);
  2264.             }
  2265.         }
  2266.     }
  2267.     else
  2268.     {
  2269.         HDC hdcScreen;
  2270.  
  2271.         hdcScreen = GetDC(mainwindow);
  2272.  
  2273.         if (windc && dibdc)
  2274.         {
  2275.             MGL_setWinDC(windc,hdcScreen);
  2276.  
  2277.             while (rects)
  2278.             {
  2279.                 if (vid_stretched)
  2280.                 {
  2281.                     MGL_stretchBltCoord(windc,dibdc,
  2282.                         rects->x, rects->y,
  2283.                         rects->x + rects->width, rects->y + rects->height,
  2284.                         rects->x << 1, rects->y << 1,
  2285.                         (rects->x + rects->width) << 1,
  2286.                         (rects->y + rects->height) << 1);
  2287.                 }
  2288.                 else
  2289.                 {
  2290.                     MGL_bitBltCoord(windc,dibdc,
  2291.                         rects->x, rects->y,
  2292.                         rects->x + rects->width, rects->y + rects->height,
  2293.                         rects->x, rects->y, MGL_REPLACE_MODE);
  2294.                 }
  2295.  
  2296.                 rects = rects->pnext;
  2297.             }
  2298.         }
  2299.  
  2300.         ReleaseDC(mainwindow, hdcScreen);
  2301.     }
  2302. }
  2303.  
  2304.  
  2305. void    VID_Update (vrect_t *rects)
  2306. {
  2307.     vrect_t    rect;
  2308.     RECT    trect;
  2309.  
  2310.     if (!vid_palettized && palette_changed)
  2311.     {
  2312.         palette_changed = false;
  2313.         rect.x = 0;
  2314.         rect.y = 0;
  2315.         rect.width = vid.width;
  2316.         rect.height = vid.height;
  2317.         rect.pnext = NULL;
  2318.         rects = ▭
  2319.     }
  2320.  
  2321.     if (firstupdate)
  2322.     {
  2323.         if (modestate == MS_WINDOWED)
  2324.         {
  2325.             GetWindowRect (mainwindow, &trect);
  2326.  
  2327.             if ((trect.left != (int)vid_window_x.value) ||
  2328.                 (trect.top  != (int)vid_window_y.value))
  2329.             {
  2330.                 if (COM_CheckParm ("-resetwinpos"))
  2331.                 {
  2332.                     Cvar_SetValue ("vid_window_x", 0.0);
  2333.                     Cvar_SetValue ("vid_window_y", 0.0);
  2334.                 }
  2335.  
  2336.                 VID_CheckWindowXY ();
  2337.                 SetWindowPos (mainwindow, NULL, (int)vid_window_x.value,
  2338.                   (int)vid_window_y.value, 0, 0,
  2339.                   SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW | SWP_DRAWFRAME);
  2340.             }
  2341.         }
  2342.  
  2343.         if ((_vid_default_mode_win.value != vid_default) &&
  2344.             (!startwindowed || (_vid_default_mode_win.value < MODE_FULLSCREEN_DEFAULT)))
  2345.         {
  2346.             firstupdate = 0;
  2347.  
  2348.             if (COM_CheckParm ("-resetwinpos"))
  2349.             {
  2350.                 Cvar_SetValue ("vid_window_x", 0.0);
  2351.                 Cvar_SetValue ("vid_window_y", 0.0);
  2352.             }
  2353.  
  2354.             if ((_vid_default_mode_win.value < 0) ||
  2355.                 (_vid_default_mode_win.value >= nummodes))
  2356.             {
  2357.                 Cvar_SetValue ("_vid_default_mode_win", windowed_default);
  2358.             }
  2359.  
  2360.             Cvar_SetValue ("vid_mode", _vid_default_mode_win.value);
  2361.         }
  2362.     }
  2363.  
  2364.     // We've drawn the frame; copy it to the screen
  2365.     FlipScreen (rects);
  2366.  
  2367.     if (vid_testingmode)
  2368.     {
  2369.         if (realtime >= vid_testendtime)
  2370.         {
  2371.             VID_SetMode (vid_realmode, vid_curpal);
  2372.             vid_testingmode = 0;
  2373.         }
  2374.     }
  2375.     else
  2376.     {
  2377.         if ((int)vid_mode.value != vid_realmode)
  2378.         {
  2379.             VID_SetMode ((int)vid_mode.value, vid_curpal);
  2380.             Cvar_SetValue ("vid_mode", (float)vid_modenum);
  2381.                                 // so if mode set fails, we don't keep on
  2382.                                 //  trying to set that mode
  2383.             vid_realmode = vid_modenum;
  2384.         }
  2385.     }
  2386.  
  2387. // handle the mouse state when windowed if that's changed
  2388.     if (modestate == MS_WINDOWED)
  2389.     {
  2390.         if ((int)_windowed_mouse.value != windowed_mouse)
  2391.         {
  2392.             if (_windowed_mouse.value)
  2393.             {
  2394.                 IN_ActivateMouse ();
  2395.                 IN_HideMouse ();
  2396.             }
  2397.             else
  2398.             {
  2399.                 IN_DeactivateMouse ();
  2400.                 IN_ShowMouse ();
  2401.             }
  2402.  
  2403.             windowed_mouse = (int)_windowed_mouse.value;
  2404.         }
  2405.     }
  2406. }
  2407.  
  2408.  
  2409. /*
  2410. ================
  2411. D_BeginDirectRect
  2412. ================
  2413. */
  2414. void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
  2415. {
  2416.     int        i, j, reps, repshift;
  2417.     vrect_t    rect;
  2418.  
  2419.     if (!vid_initialized)
  2420.         return;
  2421.  
  2422.     if (vid.aspect > 1.5)
  2423.     {
  2424.         reps = 2;
  2425.         repshift = 1;
  2426.     }
  2427.     else
  2428.     {
  2429.         reps = 1;
  2430.         repshift = 0;
  2431.     }
  2432.  
  2433.     if (vid.numpages == 1)
  2434.     {
  2435.         VID_LockBuffer ();
  2436.  
  2437.         if (!vid.direct)
  2438.             Sys_Error ("NULL vid.direct pointer");
  2439.  
  2440.         for (i=0 ; i<(height << repshift) ; i += reps)
  2441.         {
  2442.             for (j=0 ; j<reps ; j++)
  2443.             {
  2444.                 memcpy (&backingbuf[(i + j) * 24],
  2445.                         vid.direct + x + ((y << repshift) + i + j) * vid.rowbytes,
  2446.                         width);
  2447.                 memcpy (vid.direct + x + ((y << repshift) + i + j) * vid.rowbytes,
  2448.                         &pbitmap[(i >> repshift) * width],
  2449.                         width);
  2450.             }
  2451.         }
  2452.  
  2453.         VID_UnlockBuffer ();
  2454.  
  2455.         rect.x = x;
  2456.         rect.y = y;
  2457.         rect.width = width;
  2458.         rect.height = height << repshift;
  2459.         rect.pnext = NULL;
  2460.  
  2461.         FlipScreen (&rect);
  2462.     }
  2463.     else
  2464.     {
  2465.     // unlock if locked
  2466.         if (lockcount > 0)
  2467.             MGL_endDirectAccess();
  2468.  
  2469.     // set the active page to the displayed page
  2470.         MGL_setActivePage (mgldc, vPage);
  2471.  
  2472.     // lock the screen
  2473.         MGL_beginDirectAccess ();
  2474.  
  2475.     // save from and draw to screen
  2476.         for (i=0 ; i<(height << repshift) ; i += reps)
  2477.         {
  2478.             for (j=0 ; j<reps ; j++)
  2479.             {
  2480.                 memcpy (&backingbuf[(i + j) * 24],
  2481.                         (byte *)mgldc->surface + x +
  2482.                          ((y << repshift) + i + j) * mgldc->mi.bytesPerLine,
  2483.                         width);
  2484.                 memcpy ((byte *)mgldc->surface + x +
  2485.                          ((y << repshift) + i + j) * mgldc->mi.bytesPerLine,
  2486.                         &pbitmap[(i >> repshift) * width],
  2487.                         width);
  2488.             }
  2489.         }
  2490.  
  2491.     // unlock the screen
  2492.         MGL_endDirectAccess ();
  2493.  
  2494.     // restore the original active page
  2495.         MGL_setActivePage (mgldc, aPage);
  2496.  
  2497.     // relock the screen if it was locked
  2498.         if (lockcount > 0)
  2499.             MGL_beginDirectAccess();
  2500.     }
  2501. }
  2502.  
  2503.  
  2504. /*
  2505. ================
  2506. D_EndDirectRect
  2507. ================
  2508. */
  2509. void D_EndDirectRect (int x, int y, int width, int height)
  2510. {
  2511.     int        i, j, reps, repshift;
  2512.     vrect_t    rect;
  2513.  
  2514.     if (!vid_initialized)
  2515.         return;
  2516.  
  2517.     if (vid.aspect > 1.5)
  2518.     {
  2519.         reps = 2;
  2520.         repshift = 1;
  2521.     }
  2522.     else
  2523.     {
  2524.         reps = 1;
  2525.         repshift = 0;
  2526.     }
  2527.  
  2528.     if (vid.numpages == 1)
  2529.     {
  2530.         VID_LockBuffer ();
  2531.  
  2532.         if (!vid.direct)
  2533.             Sys_Error ("NULL vid.direct pointer");
  2534.  
  2535.         for (i=0 ; i<(height << repshift) ; i += reps)
  2536.         {
  2537.             for (j=0 ; j<reps ; j++)
  2538.             {
  2539.                 memcpy (vid.direct + x + ((y << repshift) + i + j) * vid.rowbytes,
  2540.                         &backingbuf[(i + j) * 24],
  2541.                         width);
  2542.             }
  2543.         }
  2544.  
  2545.         VID_UnlockBuffer ();
  2546.  
  2547.         rect.x = x;
  2548.         rect.y = y;
  2549.         rect.width = width;
  2550.         rect.height = height << repshift;
  2551.         rect.pnext = NULL;
  2552.  
  2553.         FlipScreen (&rect);
  2554.     }
  2555.     else
  2556.     {
  2557.     // unlock if locked
  2558.         if (lockcount > 0)
  2559.             MGL_endDirectAccess();
  2560.  
  2561.     // set the active page to the displayed page
  2562.         MGL_setActivePage (mgldc, vPage);
  2563.  
  2564.     // lock the screen
  2565.         MGL_beginDirectAccess ();
  2566.  
  2567.     // restore to the screen
  2568.         for (i=0 ; i<(height << repshift) ; i += reps)
  2569.         {
  2570.             for (j=0 ; j<reps ; j++)
  2571.             {
  2572.                 memcpy ((byte *)mgldc->surface + x +
  2573.                          ((y << repshift) + i + j) * mgldc->mi.bytesPerLine,
  2574.                         &backingbuf[(i + j) * 24],
  2575.                         width);
  2576.             }
  2577.         }
  2578.  
  2579.     // unlock the screen
  2580.         MGL_endDirectAccess ();
  2581.  
  2582.     // restore the original active page
  2583.         MGL_setActivePage (mgldc, aPage);
  2584.  
  2585.     // relock the screen if it was locked
  2586.         if (lockcount > 0)
  2587.             MGL_beginDirectAccess();
  2588.     }
  2589. }
  2590.  
  2591.  
  2592. //==========================================================================
  2593.  
  2594. byte        scantokey[128] = 
  2595.                     { 
  2596. //  0           1       2       3       4       5       6       7 
  2597. //  8           9       A       B       C       D       E       F 
  2598.     0  ,    27,     '1',    '2',    '3',    '4',    '5',    '6', 
  2599.     '7',    '8',    '9',    '0',    '-',    '=',    K_BACKSPACE, 9, // 0 
  2600.     'q',    'w',    'e',    'r',    't',    'y',    'u',    'i', 
  2601.     'o',    'p',    '[',    ']',    13 ,    K_CTRL,'a',  's',      // 1 
  2602.     'd',    'f',    'g',    'h',    'j',    'k',    'l',    ';', 
  2603.     '\'' ,    '`',    K_SHIFT,'\\',  'z',    'x',    'c',    'v',      // 2 
  2604.     'b',    'n',    'm',    ',',    '.',    '/',    K_SHIFT,'*', 
  2605.     K_ALT,' ',   0  ,    K_F1, K_F2, K_F3, K_F4, K_F5,   // 3 
  2606.     K_F6, K_F7, K_F8, K_F9, K_F10,  K_PAUSE,    0  , K_HOME, 
  2607.     K_UPARROW,K_PGUP,'-',K_LEFTARROW,'5',K_RIGHTARROW,'+',K_END, //4 
  2608.     K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0,             0,              K_F11, 
  2609.     K_F12,0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,        // 5
  2610.     0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0, 
  2611.     0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,        // 6 
  2612.     0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0, 
  2613.     0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0         // 7 
  2614. }; 
  2615.  
  2616. /*
  2617. =======
  2618. MapKey
  2619.  
  2620. Map from windows to quake keynums
  2621. =======
  2622. */
  2623. int MapKey (int key)
  2624. {
  2625.     key = (key>>16)&255;
  2626.     if (key > 127)
  2627.         return 0;
  2628.  
  2629.     return scantokey[key];
  2630. }
  2631.  
  2632. void AppActivate(BOOL fActive, BOOL minimize)
  2633. /****************************************************************************
  2634. *
  2635. * Function:     AppActivate
  2636. * Parameters:   fActive - True if app is activating
  2637. *
  2638. * Description:  If the application is activating, then swap the system
  2639. *               into SYSPAL_NOSTATIC mode so that our palettes will display
  2640. *               correctly.
  2641. *
  2642. ****************************************************************************/
  2643. {
  2644.     HDC            hdc;
  2645.     int            i, t;
  2646.     static BOOL    sound_active;
  2647.  
  2648.     ActiveApp = fActive;
  2649.  
  2650. // messy, but it seems to work
  2651.     if (vid_fulldib_on_focus_mode)
  2652.     {
  2653.         Minimized = minimize;
  2654.  
  2655.         if (Minimized)
  2656.             ActiveApp = false;
  2657.     }
  2658.  
  2659.     MGL_appActivate(windc, ActiveApp);
  2660.  
  2661.     if (vid_initialized)
  2662.     {
  2663.     // yield the palette if we're losing the focus
  2664.         hdc = GetDC(NULL);
  2665.  
  2666.         if (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE)
  2667.         {
  2668.             if (ActiveApp)
  2669.             {
  2670.                 if ((modestate == MS_WINDOWED) || (modestate == MS_FULLDIB))
  2671.                 {
  2672.                     if (GetSystemPaletteUse(hdc) == SYSPAL_STATIC)
  2673.                     {
  2674.                     // switch to SYSPAL_NOSTATIC and remap the colors
  2675.                         SetSystemPaletteUse(hdc, SYSPAL_NOSTATIC);
  2676.                         syscolchg = true;
  2677.                         pal_is_nostatic = true;
  2678.                     }
  2679.                 }
  2680.             }
  2681.             else if (pal_is_nostatic)
  2682.             {
  2683.                 if (GetSystemPaletteUse(hdc) == SYSPAL_NOSTATIC)
  2684.                 {
  2685.                 // switch back to SYSPAL_STATIC and the old mapping
  2686.                     SetSystemPaletteUse(hdc, SYSPAL_STATIC);
  2687.                     syscolchg = true;
  2688.                 }
  2689.  
  2690.                 pal_is_nostatic = false;
  2691.             }
  2692.         }
  2693.  
  2694.         if (!Minimized)
  2695.             VID_SetPalette (vid_curpal);
  2696.  
  2697.         scr_fullupdate = 0;
  2698.  
  2699.         ReleaseDC(NULL,hdc);
  2700.     }
  2701.  
  2702. // enable/disable sound on focus gain/loss
  2703.     if (!ActiveApp && sound_active)
  2704.     {
  2705.         S_BlockSound ();
  2706.         S_ClearBuffer ();
  2707.         sound_active = false;
  2708.     }
  2709.     else if (ActiveApp && !sound_active)
  2710.     {
  2711.         S_UnblockSound ();
  2712.         S_ClearBuffer ();
  2713.         sound_active = true;
  2714.     }
  2715.  
  2716. // minimize/restore fulldib windows/mouse-capture normal windows on demand
  2717.     if (!in_mode_set)
  2718.     {
  2719.         if (ActiveApp)
  2720.         {
  2721.             if (vid_fulldib_on_focus_mode)
  2722.             {
  2723.                 if (vid_initialized)
  2724.                 {
  2725.                     msg_suppress_1 = true;    // don't want to see normal mode set message
  2726.                     VID_SetMode (vid_fulldib_on_focus_mode, vid_curpal);
  2727.                     msg_suppress_1 = false;
  2728.  
  2729.                     t = in_mode_set;
  2730.                     in_mode_set = true;
  2731.                     AppActivate (true, false);
  2732.                     in_mode_set = t;
  2733.                 }
  2734.  
  2735.                 IN_ActivateMouse ();
  2736.                 IN_HideMouse ();
  2737.             }
  2738.             else if ((modestate == MS_WINDOWED) && _windowed_mouse.value)
  2739.             {
  2740.                 IN_ActivateMouse ();
  2741.                 IN_HideMouse ();
  2742.             }
  2743.         }
  2744.  
  2745.         if (!ActiveApp)
  2746.         {
  2747.             if (modestate == MS_FULLDIB)
  2748.             {
  2749.                 if (vid_initialized)
  2750.                 {
  2751.                     force_minimized = true;
  2752.                     i = vid_fulldib_on_focus_mode;
  2753.                     msg_suppress_1 = true;    // don't want to see normal mode set message
  2754.                     VID_SetMode (windowed_default, vid_curpal);
  2755.                     msg_suppress_1 = false;
  2756.                     vid_fulldib_on_focus_mode = i;
  2757.                     force_minimized = false;
  2758.  
  2759.                 // we never seem to get WM_ACTIVATE inactive from this mode set, so we'll
  2760.                 // do it manually
  2761.                     t = in_mode_set;
  2762.                     in_mode_set = true;
  2763.                     AppActivate (false, true);
  2764.                     in_mode_set = t;
  2765.                 }
  2766.  
  2767.                 IN_DeactivateMouse ();
  2768.                 IN_ShowMouse ();
  2769.             }
  2770.             else if ((modestate == MS_WINDOWED) && _windowed_mouse.value)
  2771.             {
  2772.                 IN_DeactivateMouse ();
  2773.                 IN_ShowMouse ();
  2774.             }
  2775.         }
  2776.     }
  2777. }
  2778.  
  2779.  
  2780. /*
  2781. ================
  2782. VID_HandlePause
  2783. ================
  2784. */
  2785. void VID_HandlePause (qboolean pause)
  2786. {
  2787.  
  2788.     if ((modestate == MS_WINDOWED) && _windowed_mouse.value)
  2789.     {
  2790.         if (pause)
  2791.         {
  2792.             IN_DeactivateMouse ();
  2793.             IN_ShowMouse ();
  2794.         }
  2795.         else
  2796.         {
  2797.             IN_ActivateMouse ();
  2798.             IN_HideMouse ();
  2799.         }
  2800.     }
  2801. }
  2802.  
  2803.  
  2804. /*
  2805. ===================================================================
  2806.  
  2807. MAIN WINDOW
  2808.  
  2809. ===================================================================
  2810. */
  2811.  
  2812. LONG CDAudio_MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  2813.  
  2814. /* main window procedure */
  2815. LONG WINAPI MainWndProc (
  2816.     HWND    hWnd,
  2817.     UINT    uMsg,
  2818.     WPARAM  wParam,
  2819.     LPARAM  lParam)
  2820. {
  2821.     LONG            lRet = 0;
  2822.     int                fwKeys, xPos, yPos, fActive, fMinimized, temp;
  2823.     HDC                hdc;
  2824.     PAINTSTRUCT        ps;
  2825.     static int        recursiveflag;
  2826.  
  2827.     switch (uMsg)
  2828.     {
  2829.         case WM_CREATE:
  2830.             break;
  2831.  
  2832.         case WM_SYSCOMMAND:
  2833.  
  2834.         // Check for maximize being hit
  2835.             switch (wParam & ~0x0F)
  2836.             {
  2837.                 case SC_MAXIMIZE:
  2838.                 // if minimized, bring up as a window before going fullscreen,
  2839.                 // so MGL will have the right state to restore
  2840.                     if (Minimized)
  2841.                     {
  2842.                         force_mode_set = true;
  2843.                         VID_SetMode (vid_modenum, vid_curpal);
  2844.                         force_mode_set = false;
  2845.                     }
  2846.  
  2847.                     VID_SetMode ((int)vid_fullscreen_mode.value, vid_curpal);
  2848.                     break;
  2849.  
  2850.                 case SC_SCREENSAVE:
  2851.                 case SC_MONITORPOWER:
  2852.                     if (modestate != MS_WINDOWED)
  2853.                     {
  2854.                     // don't call DefWindowProc() because we don't want to start
  2855.                     // the screen saver fullscreen
  2856.                         break;
  2857.                     }
  2858.  
  2859.                 // fall through windowed and allow the screen saver to start
  2860.  
  2861.                 default:
  2862.                     if (!in_mode_set)
  2863.                     {
  2864.                         S_BlockSound ();
  2865.                         S_ClearBuffer ();
  2866.                     }
  2867.  
  2868.                     lRet = DefWindowProc (hWnd, uMsg, wParam, lParam);
  2869.  
  2870.                     if (!in_mode_set)
  2871.                     {
  2872.                         S_UnblockSound ();
  2873.                     }
  2874.             }
  2875.             break;
  2876.  
  2877.         case WM_MOVE:
  2878.             window_x = (int) LOWORD(lParam);
  2879.             window_y = (int) HIWORD(lParam);
  2880.             VID_UpdateWindowStatus ();
  2881.  
  2882.             if ((modestate == MS_WINDOWED) && !in_mode_set && !Minimized)
  2883.                 VID_RememberWindowPos ();
  2884.  
  2885.             break;
  2886.  
  2887.         case WM_SIZE:
  2888.             Minimized = false;
  2889.             
  2890.             if (!(wParam & SIZE_RESTORED))
  2891.             {
  2892.                 if (wParam & SIZE_MINIMIZED)
  2893.                     Minimized = true;
  2894.             }
  2895.             break;
  2896.  
  2897.         case WM_SYSCHAR:
  2898.         // keep Alt-Space from happening
  2899.             break;
  2900.  
  2901.         case WM_ACTIVATE:
  2902.             fActive = LOWORD(wParam);
  2903.             fMinimized = (BOOL) HIWORD(wParam);
  2904.             AppActivate(!(fActive == WA_INACTIVE), fMinimized);
  2905.  
  2906.         // fix the leftover Alt from any Alt-Tab or the like that switched us away
  2907.             ClearAllStates ();
  2908.  
  2909.             if (!in_mode_set)
  2910.             {
  2911.                 if (windc)
  2912.                     MGL_activatePalette(windc,true);
  2913.  
  2914.                 VID_SetPalette(vid_curpal);
  2915.             }
  2916.  
  2917.             break;
  2918.  
  2919.         case WM_PAINT:
  2920.             hdc = BeginPaint(hWnd, &ps);
  2921.  
  2922.             if (!in_mode_set && host_initialized)
  2923.                 SCR_UpdateWholeScreen ();
  2924.  
  2925.             EndPaint(hWnd, &ps);
  2926.             break;
  2927.  
  2928.         case WM_KEYDOWN:
  2929.         case WM_SYSKEYDOWN:
  2930.             if (!in_mode_set)
  2931.                 Key_Event (MapKey(lParam), true);
  2932.             break;
  2933.  
  2934.         case WM_KEYUP:
  2935.         case WM_SYSKEYUP:
  2936.             if (!in_mode_set)
  2937.                 Key_Event (MapKey(lParam), false);
  2938.             break;
  2939.  
  2940.     // this is complicated because Win32 seems to pack multiple mouse events into
  2941.     // one update sometimes, so we always check all states and look for events
  2942.         case WM_LBUTTONDOWN:
  2943.         case WM_LBUTTONUP:
  2944.         case WM_RBUTTONDOWN:
  2945.         case WM_RBUTTONUP:
  2946.         case WM_MBUTTONDOWN:
  2947.         case WM_MBUTTONUP:
  2948.         case WM_MOUSEMOVE:
  2949.             if (!in_mode_set)
  2950.             {
  2951.                 temp = 0;
  2952.  
  2953.                 if (wParam & MK_LBUTTON)
  2954.                     temp |= 1;
  2955.  
  2956.                 if (wParam & MK_RBUTTON)
  2957.                     temp |= 2;
  2958.  
  2959.                 if (wParam & MK_MBUTTON)
  2960.                     temp |= 4;
  2961.  
  2962.                 IN_MouseEvent (temp);
  2963.             }
  2964.             break;
  2965.  
  2966.         // JACK: This is the mouse wheel with the Intellimouse
  2967.         // Its delta is either positive or neg, and we generate the proper
  2968.         // Event.
  2969.         case WM_MOUSEWHEEL: 
  2970.             if ((short) HIWORD(wParam) > 0) {
  2971.                 Key_Event(K_MWHEELUP, true);
  2972.                 Key_Event(K_MWHEELUP, false);
  2973.             } else {
  2974.                 Key_Event(K_MWHEELDOWN, true);
  2975.                 Key_Event(K_MWHEELDOWN, false);
  2976.             }
  2977.             break;
  2978.         // KJB: Added these new palette functions
  2979.         case WM_PALETTECHANGED:
  2980.             if ((HWND)wParam == hWnd)
  2981.                 break;
  2982.             /* Fall through to WM_QUERYNEWPALETTE */
  2983.         case WM_QUERYNEWPALETTE:
  2984.             hdc = GetDC(NULL);
  2985.  
  2986.             if (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE)
  2987.                 vid_palettized = true;
  2988.             else
  2989.                 vid_palettized = false;
  2990.  
  2991.             ReleaseDC(NULL,hdc);
  2992.  
  2993.             scr_fullupdate = 0;
  2994.  
  2995.             if (vid_initialized && !in_mode_set && windc && MGL_activatePalette(windc,false) && !Minimized)
  2996.             {
  2997.                 VID_SetPalette (vid_curpal);
  2998.                 InvalidateRect (mainwindow, NULL, false);
  2999.  
  3000.             // specifically required if WM_QUERYNEWPALETTE realizes a new palette
  3001.                 lRet = TRUE;
  3002.             }
  3003.             break;
  3004.  
  3005.         case WM_DISPLAYCHANGE:
  3006.             if (!in_mode_set && (modestate == MS_WINDOWED) && !vid_fulldib_on_focus_mode)
  3007.             {
  3008.                 force_mode_set = true;
  3009.                 VID_SetMode (vid_modenum, vid_curpal);
  3010.                 force_mode_set = false;
  3011.             }
  3012.             break;
  3013.  
  3014.            case WM_CLOSE:
  3015.         // this causes Close in the right-click task bar menu not to work, but right
  3016.         // now bad things happen if Close is handled in that case (garbage and a
  3017.         // crash on Win95)
  3018.             if (!in_mode_set)
  3019.             {
  3020.                 if (MessageBox (mainwindow, "Are you sure you want to quit?", "Confirm Exit",
  3021.                             MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION) == IDYES)
  3022.                 {
  3023.                     Sys_Quit ();
  3024.                 }
  3025.             }
  3026.             break;
  3027.  
  3028.         case MM_MCINOTIFY:
  3029.             lRet = CDAudio_MessageHandler (hWnd, uMsg, wParam, lParam);
  3030.             break;
  3031.  
  3032.         default:
  3033.             /* pass all unhandled messages to DefWindowProc */
  3034.             lRet = DefWindowProc (hWnd, uMsg, wParam, lParam);
  3035.             break;
  3036.     }
  3037.  
  3038.     /* return 0 if handled message, 1 if not */
  3039.     return lRet;
  3040. }
  3041.  
  3042.  
  3043. extern void M_Menu_Options_f (void);
  3044. extern void M_Print (int cx, int cy, char *str);
  3045. extern void M_PrintWhite (int cx, int cy, char *str);
  3046. extern void M_DrawCharacter (int cx, int line, int num);
  3047. extern void M_DrawTransPic (int x, int y, qpic_t *pic);
  3048. extern void M_DrawPic (int x, int y, qpic_t *pic);
  3049.  
  3050. static int    vid_line, vid_wmodes;
  3051.  
  3052. typedef struct
  3053. {
  3054.     int        modenum;
  3055.     char    *desc;
  3056.     int        iscur;
  3057.     int        ismode13;
  3058.     int        width;
  3059. } modedesc_t;
  3060.  
  3061. #define MAX_COLUMN_SIZE        5
  3062. #define MODE_AREA_HEIGHT    (MAX_COLUMN_SIZE + 6)
  3063. #define MAX_MODEDESCS        (MAX_COLUMN_SIZE*3)
  3064.  
  3065. static modedesc_t    modedescs[MAX_MODEDESCS];
  3066.  
  3067. /*
  3068. ================
  3069. VID_MenuDraw
  3070. ================
  3071. */
  3072. void VID_MenuDraw (void)
  3073. {
  3074.     qpic_t        *p;
  3075.     char        *ptr;
  3076.     int            lnummodes, i, j, k, column, row, dup, dupmode;
  3077.     char        temp[100];
  3078.     vmode_t        *pv;
  3079.     modedesc_t    tmodedesc;
  3080.  
  3081.     p = Draw_CachePic ("gfx/vidmodes.lmp");
  3082.     M_DrawPic ( (320-p->width)/2, 4, p);
  3083.  
  3084.     for (i=0 ; i<3 ; i++)
  3085.     {
  3086.         ptr = VID_GetModeDescriptionMemCheck (i);
  3087.         modedescs[i].modenum = modelist[i].modenum;
  3088.         modedescs[i].desc = ptr;
  3089.         modedescs[i].ismode13 = 0;
  3090.         modedescs[i].iscur = 0;
  3091.  
  3092.         if (vid_modenum == i)
  3093.             modedescs[i].iscur = 1;
  3094.     }
  3095.  
  3096.     vid_wmodes = 3;
  3097.     lnummodes = VID_NumModes ();
  3098.     
  3099.     for (i=3 ; i<lnummodes ; i++)
  3100.     {
  3101.         ptr = VID_GetModeDescriptionMemCheck (i);
  3102.         pv = VID_GetModePtr (i);
  3103.  
  3104.     // we only have room for 15 fullscreen modes, so don't allow
  3105.     // 360-wide modes, because if there are 5 320-wide modes and
  3106.     // 5 360-wide modes, we'll run out of space
  3107.         if (ptr && ((pv->width != 360) || COM_CheckParm("-allow360")))
  3108.         {
  3109.             dup = 0;
  3110.  
  3111.             for (j=3 ; j<vid_wmodes ; j++)
  3112.             {
  3113.                 if (!strcmp (modedescs[j].desc, ptr))
  3114.                 {
  3115.                     dup = 1;
  3116.                     dupmode = j;
  3117.                     break;
  3118.                 }
  3119.             }
  3120.  
  3121.             if (dup || (vid_wmodes < MAX_MODEDESCS))       
  3122.             {
  3123.                 if (!dup || !modedescs[dupmode].ismode13 || COM_CheckParm("-noforcevga"))
  3124.                 {
  3125.                     if (dup)
  3126.                     {
  3127.                         k = dupmode;
  3128.                     }
  3129.                     else
  3130.                     {
  3131.                         k = vid_wmodes;
  3132.                     }
  3133.  
  3134.                     modedescs[k].modenum = i;
  3135.                     modedescs[k].desc = ptr;
  3136.                     modedescs[k].ismode13 = pv->mode13;
  3137.                     modedescs[k].iscur = 0;
  3138.                     modedescs[k].width = pv->width;
  3139.  
  3140.                     if (i == vid_modenum)
  3141.                         modedescs[k].iscur = 1;
  3142.  
  3143.                     if (!dup)
  3144.                         vid_wmodes++;
  3145.                 }
  3146.             }
  3147.         }
  3148.     }
  3149.  
  3150. // sort the modes on width (to handle picking up oddball dibonly modes
  3151. // after all the others)
  3152.     for (i=3 ; i<(vid_wmodes-1) ; i++)
  3153.     {
  3154.         for (j=(i+1) ; j<vid_wmodes ; j++)
  3155.         {
  3156.             if (modedescs[i].width > modedescs[j].width)
  3157.             {
  3158.                 tmodedesc = modedescs[i];
  3159.                 modedescs[i] = modedescs[j];
  3160.                 modedescs[j] = tmodedesc;
  3161.             }
  3162.         }
  3163.     }
  3164.  
  3165.  
  3166.     M_Print (13*8, 36, "Windowed Modes");
  3167.  
  3168.     column = 16;
  3169.     row = 36+2*8;
  3170.  
  3171.     for (i=0 ; i<3; i++)
  3172.     {
  3173.         if (modedescs[i].iscur)
  3174.             M_PrintWhite (column, row, modedescs[i].desc);
  3175.         else
  3176.             M_Print (column, row, modedescs[i].desc);
  3177.  
  3178.         column += 13*8;
  3179.     }
  3180.  
  3181.     if (vid_wmodes > 3)
  3182.     {
  3183.         M_Print (12*8, 36+4*8, "Fullscreen Modes");
  3184.  
  3185.         column = 16;
  3186.         row = 36+6*8;
  3187.  
  3188.         for (i=3 ; i<vid_wmodes ; i++)
  3189.         {
  3190.             if (modedescs[i].iscur)
  3191.                 M_PrintWhite (column, row, modedescs[i].desc);
  3192.             else
  3193.                 M_Print (column, row, modedescs[i].desc);
  3194.  
  3195.             column += 13*8;
  3196.  
  3197.             if (((i - 3) % VID_ROW_SIZE) == (VID_ROW_SIZE - 1))
  3198.             {
  3199.                 column = 16;
  3200.                 row += 8;
  3201.             }
  3202.         }
  3203.     }
  3204.  
  3205. // line cursor
  3206.     if (vid_testingmode)
  3207.     {
  3208.         sprintf (temp, "TESTING %s",
  3209.                 modedescs[vid_line].desc);
  3210.         M_Print (13*8, 36 + MODE_AREA_HEIGHT * 8 + 8*4, temp);
  3211.         M_Print (9*8, 36 + MODE_AREA_HEIGHT * 8 + 8*6,
  3212.                 "Please wait 5 seconds...");
  3213.     }
  3214.     else
  3215.     {
  3216.         M_Print (9*8, 36 + MODE_AREA_HEIGHT * 8 + 8,
  3217.                 "Press Enter to set mode");
  3218.         M_Print (6*8, 36 + MODE_AREA_HEIGHT * 8 + 8*3,
  3219.                 "T to test mode for 5 seconds");
  3220.         ptr = VID_GetModeDescription2 (vid_modenum);
  3221.  
  3222.         if (ptr)
  3223.         {
  3224.             sprintf (temp, "D to set default: %s", ptr);
  3225.             M_Print (2*8, 36 + MODE_AREA_HEIGHT * 8 + 8*5, temp);
  3226.         }
  3227.  
  3228.         ptr = VID_GetModeDescription2 ((int)_vid_default_mode_win.value);
  3229.  
  3230.         if (ptr)
  3231.         {
  3232.             sprintf (temp, "Current default: %s", ptr);
  3233.             M_Print (3*8, 36 + MODE_AREA_HEIGHT * 8 + 8*6, temp);
  3234.         }
  3235.  
  3236.         M_Print (15*8, 36 + MODE_AREA_HEIGHT * 8 + 8*8,
  3237.                 "Esc to exit");
  3238.  
  3239.         row = 36 + 2*8 + (vid_line / VID_ROW_SIZE) * 8;
  3240.         column = 8 + (vid_line % VID_ROW_SIZE) * 13*8;
  3241.  
  3242.         if (vid_line >= 3)
  3243.             row += 3*8;
  3244.  
  3245.         M_DrawCharacter (column, row, 12+((int)(realtime*4)&1));
  3246.     }
  3247. }
  3248.  
  3249.  
  3250. /*
  3251. ================
  3252. VID_MenuKey
  3253. ================
  3254. */
  3255. void VID_MenuKey (int key)
  3256. {
  3257.     if (vid_testingmode)
  3258.         return;
  3259.  
  3260.     switch (key)
  3261.     {
  3262.     case K_ESCAPE:
  3263.         S_LocalSound ("misc/menu1.wav");
  3264.         M_Menu_Options_f ();
  3265.         break;
  3266.  
  3267.     case K_LEFTARROW:
  3268.         S_LocalSound ("misc/menu1.wav");
  3269.         vid_line = ((vid_line / VID_ROW_SIZE) * VID_ROW_SIZE) +
  3270.                    ((vid_line + 2) % VID_ROW_SIZE);
  3271.  
  3272.         if (vid_line >= vid_wmodes)
  3273.             vid_line = vid_wmodes - 1;
  3274.         break;
  3275.  
  3276.     case K_RIGHTARROW:
  3277.         S_LocalSound ("misc/menu1.wav");
  3278.         vid_line = ((vid_line / VID_ROW_SIZE) * VID_ROW_SIZE) +
  3279.                    ((vid_line + 4) % VID_ROW_SIZE);
  3280.  
  3281.         if (vid_line >= vid_wmodes)
  3282.             vid_line = (vid_line / VID_ROW_SIZE) * VID_ROW_SIZE;
  3283.         break;
  3284.  
  3285.     case K_UPARROW:
  3286.         S_LocalSound ("misc/menu1.wav");
  3287.         vid_line -= VID_ROW_SIZE;
  3288.  
  3289.         if (vid_line < 0)
  3290.         {
  3291.             vid_line += ((vid_wmodes + (VID_ROW_SIZE - 1)) /
  3292.                     VID_ROW_SIZE) * VID_ROW_SIZE;
  3293.  
  3294.             while (vid_line >= vid_wmodes)
  3295.                 vid_line -= VID_ROW_SIZE;
  3296.         }
  3297.         break;
  3298.  
  3299.     case K_DOWNARROW:
  3300.         S_LocalSound ("misc/menu1.wav");
  3301.         vid_line += VID_ROW_SIZE;
  3302.  
  3303.         if (vid_line >= vid_wmodes)
  3304.         {
  3305.             vid_line -= ((vid_wmodes + (VID_ROW_SIZE - 1)) /
  3306.                     VID_ROW_SIZE) * VID_ROW_SIZE;
  3307.  
  3308.             while (vid_line < 0)
  3309.                 vid_line += VID_ROW_SIZE;
  3310.         }
  3311.         break;
  3312.  
  3313.     case K_ENTER:
  3314.         S_LocalSound ("misc/menu1.wav");
  3315.         VID_SetMode (modedescs[vid_line].modenum, vid_curpal);
  3316.         break;
  3317.  
  3318.     case 'T':
  3319.     case 't':
  3320.         S_LocalSound ("misc/menu1.wav");
  3321.     // have to set this before setting the mode because WM_PAINT
  3322.     // happens during the mode set and does a VID_Update, which
  3323.     // checks vid_testingmode
  3324.         vid_testingmode = 1;
  3325.         vid_testendtime = realtime + 5.0;
  3326.  
  3327.         if (!VID_SetMode (modedescs[vid_line].modenum, vid_curpal))
  3328.         {
  3329.             vid_testingmode = 0;
  3330.         }
  3331.         break;
  3332.  
  3333.     case 'D':
  3334.     case 'd':
  3335.         S_LocalSound ("misc/menu1.wav");
  3336.         firstupdate = 0;
  3337.         Cvar_SetValue ("_vid_default_mode_win", vid_modenum);
  3338.         break;
  3339.  
  3340.     default:
  3341.         break;
  3342.     }
  3343. }
  3344.